In my code I create an instance of the ScrollingBackground in the BackgroundLayer and the BackgroundLayer also creates an instance in the GameScene. I want to save the ScrollingBackground state so when a player dies I can return to it unchanged. Here is the relevant code:
ScrollingBackground.m:
-(id)initWithBackgroundLayer: (BackgroundLayer *)layer{
if (self = [super init]) {
backgroundRepeatCount =0;
scrollSpeed = 0.0;
backgroundCount = 0;
backgroundArray = [[NSMutableArray alloc] init]
bg = [CCSprite spriteWithSpriteFrameName:#"bg1.png"];
bg.position = ccp(s.width/2, s.height/2);
[currentBatchNode addChild:bg];
bgSwap = [CCSprite spriteWithSpriteFrameName:#"bg2.png"];
bgSwap.position = ccp(s.width/2, 3*s.height/2 -1.0);
[currentBatchNode addChild: bgSwap];
.
.
.
}
}
-(void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:self.bg forKey:#"bg"];
[aCoder encodeObject:self.bgSwap forKey:#"bgSwap"];
[aCoder encodeObject:self.displayedBg forKey:#"displayedBg"];
[aCoder encodeObject:self.backgroundArray forKey:#"backgroundArray"];
[aCoder encodeObject:self.currentBatchNode forKey:#"currentBatchNode"];
.
.
.
}
-(id) initWithCoder:(NSCoder *) aDecoder {
self = [super init];
if(self != nil) {
self.bg = [aDecoder decodeObjectForKey:#"bg"];
self.bgSwap = [aDecoder decodeObjectForKey:#"bgSwap"];
self.displayedBg = [aDecoder decodeObjectForKey:#"displayedBg"];
self.backgroundArray = [aDecoder decodeObjectForKey:#"backgroundArray"];
self.currentBatchNode = [aDecoder decodeObjectForKey:#"currentBatchNode"];
.
.
.
}
}
EDITED:
How can I save the above state?
How can I load it again?
Is this the right way to save CCSprites and CCSpriteBatchNodes?
Related
In my effort to save a ScrollingBackground object I've subclassed the CCSprites to conform to NSCoding. The ScrollingBackground doesn't display. Please see the relevant code below. I'm not really sure whats wrong. Please help.
ScrollingBackground.h:
(CCBackgroundSprite's interface)
#interface CCBackgroundSprite: NSObject <NSCoding>
#property (nonatomic, assign) float xValue;
#property (nonatomic, assign) float yValue;
#property (nonatomic, retain) NSString* backgroundStringName;
#end
ScrollingBackground.m:
(CCBackgroundSprite's implementation)
#implementation CCBackgroundSprite
-(id)init
{
if((self = [super init])){
}
return self;
}
-(id) initWithCoder:(NSCoder *) aDecoder {
self = [super init];
if(self != nil) {
self.xValue = [aDecoder decodeFloatForKey:#"xValue"];
self.yValue = [aDecoder decodeFloatForKey:#"yValue"];
self.backgroundStringName = [aDecoder decodeObjectForKey:#"backgroundStringName"];
}
return self;
}
-(void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeFloat:self.xValue forKey:#"xValue"];
[aCoder encodeFloat:self.yValue forKey:#"yValue"];
[aCoder encodeObject:self.backgroundStringName forKey:#"backgroundStringName"];
}
#end
Setting CCBackgroundSprite's instances for the CCSprite properties:
-(void)spriteProperties {
background1 = [[CCBackgroundSprite alloc] init];
[background1 setXValue:bg.position.x];
[background1 setYValue:bg.position.y];
[background1 setBackgroundStringName:#"bg"];
background2 = [[CCBackgroundSprite alloc] init];
[background2 setXValue:bgSwap.position.x];
[background2 setYValue:bgSwap.position.y];
[background2 setBackgroundStringName:#"bgSwap"];
background3 = [[CCBackgroundSprite alloc] init];
[background3 setXValue:bgSwap2.position.x];
[background3 setYValue:bgSwap2.position.y];
[background3 setBackgroundStringName:#"bgSwap2"];
}
encoding/decoding of other non-Sprite related properties of the ScrollingBackground:
-(void) encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeInt:self.backgroundCount forKey:#"backgroundCount"];
[aCoder encodeInt:self.backgroundRepeatCount forKey:#"backgroundRepeatCount"];
[aCoder encodeFloat:self.scrollSpeed forKey:#"scrollSpeed"];
[aCoder encodeObject:self.backgroundArray forKey:#"backgroundArray"];
[aCoder encodeObject:self.changeArray forKey:#"changeArray"];
.
.
.
}
-(id) initWithCoder:(NSCoder *) aDecoder {
self = [super init];
if(self != nil) {
self.backgroundCount = [aDecoder decodeIntForKey:#"backgroundCount"];
self.backgroundRepeatCount = [aDecoder decodeIntForKey:#"backgroundRepeatCount"];
self.scrollSpeed = [aDecoder decodeFloatForKey:#"scrollSpeed"];
self.backgroundArray = [aDecoder decodeObjectForKey:#"backgroundArray"];
self.changeArray = [aDecoder decodeObjectForKey:#"changeArray"];
.
.
.
}
}
Saving and loading of ScrollingBackground object:
- (void)saveBackgroundObject:(ScrollingBackground *)object key:(NSString *)key {
[self spriteProperties];
NSData *encodedObject = [NSKeyedArchiver archivedDataWithRootObject:object];
NSString *dataToString = [NSString stringWithFormat:#"%#", encodedObject];
CCLOG(#"encodedObject = %# \n", dataToString);
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:encodedObject forKey:key];
[defaults synchronize];
}
-(ScrollingBackground *)loadBackgroundWithKey:(NSString *)key {
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSData *encodedObject = [defaults objectForKey:key];
NSString *dataToString = [NSString stringWithFormat:#"%#", encodedObject];
CCLOG(#"encodedObject = %# \n", dataToString);
ScrollingBackground *object = [NSKeyedUnarchiver unarchiveObjectWithData:encodedObject];
return object;
}
UPDATED:
I have made the following changes the spriteProperties method:
-(void)spriteProperties {
background1 = [[CCBackgroundSprite alloc] init];
[background1 setXValue:bg.position.x];
[background1 setYValue:bg.position.y];
[background1 setBackgroundImageName:bg.displayFrame.textureFilename];
[self addChild:background1];
background2 = [[CCBackgroundSprite alloc] init];
[background2 setXValue:bgSwap.position.x];
[background2 setYValue:bgSwap.position.y];
[background2 setBackgroundImageName:bgSwap.displayFrame.textureFilename];
[self addChild:background2];
background3 = [[CCBackgroundSprite alloc] init];
[background3 setXValue:bgSwap2.position.x];
[background3 setYValue:bgSwap2.position.y];
[background3 setBackgroundImageName:bgSwap2.displayFrame.textureFilename];
[self addChild:background3];
}
The main reason I am using displayFrame.textureFilename above is because I'm reusing the sprites along the way.
Also to setup of the background images I did:
-(void)startingSprites //change later to setupInitialBackground
{
CGSize s = [[CCDirector sharedDirector] winSize];
bg = [CCSprite spriteWithSpriteFrameName:#"bgImage1.png"];
bg.position = ccp(s.width/2, s.height/2);
[currentBackgroundBatchNode addChild:bg];
swapbg = [CCSprite spriteWithSpriteFrameName:#"bgImage2.png"];
swapbg.position = ccp(s.width/2, 3*s.height/2 -1.0);
[currentBackgroundBatchNode addChild: swapbg];
swapbg2 = [CCSprite spriteWithSpriteFrameName:#"bgImage3.png"];
swapbg2.position = ccp(s.width/2, 5*s.height/2 - 2.0);
[currentBackgroundBatchNode addChild: swapbg2];
CCLOG(#"bg background is %#", bg.displayFrame.textureFilename);
CCLOG(#"bgSwap background is %#", swapbg.displayFrame.textureFilename);
CCLOG(#"bgSwap2 background is %#", swapbg2.displayFrame.textureFilename);
}
I've just realized a few things:
the CCLOG's in startingSprites are null
I reuse the currentBackgroundBatchNode (which is a CCSpriteBatchNode) along the way, meaning that I have to encode/decode it. How do I subclass it and with what properties? Not too sure how it'll work out.
I have read a number of your posts, also related to this. I would recommend that instead of trying to subclass several cocos2d classes to conform to NSCoding you should use a simpler work around. I believe your background has it's own layer, so why don't you rather save various background parameters and create another init for your background to handle cases for reloading the background state.
You say you've subclassed CCSprite, but you actually subclassed NSObject. Try:
#interface CCBackgroundSprite: CCSprite <NSCoding>
...
I have subclassed a CCSprite to make an object that can be encoded and decoded. I want to save sprites state and load it again at particular positions. Everything seems to be okay apart from decoding with NSKeyedUnarchiver (see loadIconSpriteState below) which gives an EXC_BAD_ACCESS Below is the code:
HelloWorldLayer.h
#interface CCIconSprite : CCSprite {
NSString *iconName;
float iconXPos;
float iconYPos;
}
#property (nonatomic, retain) NSString *iconName;
#property (nonatomic, assign) float iconXPos;
#property (nonatomic, assign) float iconYPos;
+ (id)iconWithType:(NSString*)imageName;
- (id)initWithIconType:(NSString*)imageName;
#end
#interface HelloWorldLayer : CCLayer < NSCoding>
{
CCIconSprite* testSprite;
BOOL savedState;
CGSize size;
CCMoveTo* moveTo;
NSMutableArray* saveSpriteArray;
NSData* savedSpriteData;
}
+(CCScene *) scene;
#end
HelloWorldLayer.m:
CCIconSprite implementation:
#implementation CCIconSprite
#synthesize iconXPos;
#synthesize iconYPos;
#synthesize iconName;
+ (id)iconWithType:(NSString*)imageName
{
return [[[[self class] alloc] initWithIconType:imageName] autorelease];
}
- (id)initWithIconType:(NSString*)imageName
{
self = [super initWithFile:imageName];
if (!self) return nil;
iconName = imageName;
self.position = ccp(iconXPos, iconYPos);
return self;
}
Encoding and decoding:
- (id)initWithCoder:(NSCoder *)decoder {
NSString* imageFileName = [decoder decodeObjectForKey:#"imageFileName"];
self = [self initWithIconType:imageFileName];
if (!self) return nil;
self.iconXPos = [decoder decodeFloatForKey:#"iconXPos"];
self.iconYPos = [decoder decodeFloatForKey:#"iconYPos"];
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:iconName forKey:#"imageFileName"];
[encoder encodeFloat:self.iconXPos forKey:#"iconXPos"];
[encoder encodeFloat:self.iconYPos forKey:#"iconYPos"];
}
#end
HelloWorldLayer implementation:
#implementation HelloWorldLayer
+(CCScene *) scene
{
CCScene *scene = [CCScene node];
HelloWorldLayer *layer = [HelloWorldLayer node];
[scene addChild: layer];
return scene;
}
-(id) init
{
if( (self=[super init]) ) {
self.scale = 0.5;
savedState = NO;
size = [[CCDirector sharedDirector] winSize];
testSprite = [CCIconSprite spriteWithFile:#"Icon.png"];
testSprite.position = ccp(size.width/4, size.width/4);
testSprite.anchorPoint = ccp(0,0);
[self addChild:testSprite];
moveTo = [CCMoveTo actionWithDuration:3 position:ccp(3*size.width/4, 3*size.width/4)];
[testSprite runAction:moveTo];
[self schedule:#selector(saveAndLoadSpriteState)];
}
return self;
}
Saving and loading state:
-(void)saveIconSpriteState {
saveSpriteArray = [[NSMutableArray alloc] init];
[saveSpriteArray addObject:testSprite];
savedSpriteData = [NSKeyedArchiver archivedDataWithRootObject:saveSpriteArray];
}
-(void)loadIconSpriteState {
[NSKeyedUnarchiver unarchiveObjectWithData:savedSpriteData];
}
-(void)saveAndLoadSpriteState {
if ((testSprite.position.x > size.width/2) && !savedState) {
savedState = YES;
[self saveIconSpriteState];
}
else if ((testSprite.position.x == 3*size.width/4) && savedState) {
savedState = NO;
[self loadIconSpriteState];
[testSprite runAction:moveTo];
}
}
#end
EDIT
After setting an exception break point I got the following error
Assertion failure in -[CCIconSprite initWithFile:]
pointing to the in line:
NSAssert(filename != nil, #"Invalid filename for sprite");
in the
-(id) initWithFile:(NSString*)filename
method of the CCSprite.m class.
Just a hunch but maybe that's it. When decoding a string, you should copy it because you don't own it at this point, nor are you assigning it to a strong or copy property.
- (id)initWithCoder:(NSCoder *)decoder {
NSString* imageFileName = [[decoder decodeObjectForKey:#"imageFileName"] copy];
self = [self initWithIconType:imageFileName];
if (!self) return nil;
...
}
If that's not it, set a breakpoint and verify that the string is indeed correct when encoding and when decoding.
here is the situation:
I have a "UITableViewController" which loads objects with RestKits "RKFetchedResultsTableController". After clicking on a cell I switch to a detail UITableViewController also driven by a "RKFetchedResultsTableController" which gives me a corresponding answer text for the selected object.
The problem is now, if I go back to the first "UITableViewController" and select another object in the table the old answer text from the previous selected object is in the detail table. If I use the "pullToRefresh" function the table gets refreshed and the correct answer is loading.
Why is the old answer from the previous object still in the tableView and not the correct answer for the new selected Object even if I tell [tableController loadTable] in the viewWillAppear method.
AppDelegate:
#
interface AppDelegate ()
#property (nonatomic, strong, readwrite) RKObjectManager *objectManager;
#property (nonatomic, strong, readwrite) RKManagedObjectStore *objectStore;
#end;
#implementation AppDelegate
#synthesize window = _window, isAuthenticated;
#synthesize objectManager;
#synthesize objectStore;
- (void)initializeRestKit
{
//self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager = [RKObjectManager managerWithBaseURLString:#"http://falling-ocean-1302.herokuapp.com"];
self.objectManager.serializationMIMEType = RKMIMETypeJSON;
self.objectManager.acceptMIMEType = RKMIMETypeJSON;
self.objectStore = [RKManagedObjectStore objectStoreWithStoreFilename:#"MMmtvzme.sqlite"];
self.objectManager.objectStore = self.objectStore;
self.objectManager.mappingProvider = [MMMappingProvider mappingProviderWithObjectStore:self.objectStore];
self.objectManager.client.cachePolicy = RKRequestCachePolicyNone;
RKLogConfigureByName("RestKit", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network", RKLogLevelTrace);
RKLogConfigureByName("RestKit/ObjectMapping", RKLogLevelTrace);
RKLogConfigureByName("RestKit/Network/Queue", RKLogLevelTrace);
// Enable automatic network activity indicator management
objectManager.client.requestQueue.showsNetworkActivityIndicatorWhenBusy = YES;
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodPOST];
[objectManager.router routeClass:[MMRequest class] toResourcePath:#"/requests" forMethod:RKRequestMethodDELETE];
[objectManager.router routeClass:[MMAnswer class] toResourcePath:#"/requests/:request_id/answers" forMethod:RKRequestMethodPOST];
}
Ok this is the code from the first UITableViewController
#interface MMMyRequestList ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestList
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = #"/requests";
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"request_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
tableController.canEditRows = YES;
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestCell";
cellMapping.reuseIdentifier = #"MMRequest";
cellMapping.rowHeight = 100.0;
[cellMapping mapKeyPath:#"title" toAttribute:#"requestLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
cellMapping.onSelectCellForObjectAtIndexPath = ^(UITableViewCell *cell, id object, NSIndexPath* indexPath)
{
MMMyRequestListAnswer * uic = [self.storyboard instantiateViewControllerWithIdentifier:#"MMMyRequestListAnswer"];
MMRequest *request = [self.tableController objectForRowAtIndexPath:indexPath];
if ([uic respondsToSelector:#selector(setRequest:)]) {
[uic setRequest:request];
}
[self.navigationController pushViewController:uic animated:YES];
};
[tableController mapObjectsWithClass:[MMRequest class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestCell" bundle:nil] forCellReuseIdentifier:#"MMRequest"];
}
- (void)objectLoader:(RKObjectLoader*)objectLoader didFailWithError:(NSError*)error {
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"Error"
message:[error localizedDescription]
delegate:nil
cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
NSLog(#"Hit error: %#", error);
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
After clicking on a cell the Detail UIViewController come into action
interface MMMyRequestListAnswer ()
#property (nonatomic, strong) RKFetchedResultsTableController *tableController;
#end
#implementation MMMyRequestListAnswer
#synthesize tableHeaderView, requestTextLabel;
#synthesize request;
#synthesize tableController;
- (void)viewDidLoad
{
[super viewDidLoad];
[self configureRKTableController];
[self configureCellMapping];
[self useCustomNib];
}
- (void)configureRKTableController{
self.tableController = [[RKObjectManager sharedManager] fetchedResultsTableControllerForTableViewController:self];
self.tableController.autoRefreshFromNetwork = YES;
self.tableController.pullToRefreshEnabled = YES;
self.tableController.resourcePath = [NSString stringWithFormat:#"/requests/%i/answers", [self.request.request_id intValue]];
self.tableController.variableHeightRows = YES;
NSSortDescriptor *descriptor = [NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:NO];
self.tableController.sortDescriptors = [NSArray arrayWithObject:descriptor];
}
- (void)configureCellMapping{
RKTableViewCellMapping *cellMapping = [RKTableViewCellMapping cellMapping];
cellMapping.cellClassName = #"MMRequestAnswerCell";
cellMapping.reuseIdentifier = #"MMAnswer";
cellMapping.rowHeight = 80.0;
[cellMapping mapKeyPath:#"text" toAttribute:#"answerLabel.text"];
[cellMapping mapKeyPath:#"user.first_name" toAttribute:#"userLabel.text"];
[tableController mapObjectsWithClass:[MMAnswer class] toTableCellsWithMapping:cellMapping];
}
- (void)useCustomNib{
[self.tableView registerNib:[UINib nibWithNibName:#"MMRequestAnswerCell" bundle:nil] forCellReuseIdentifier:#"MMAnswer"];
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
/**
Load the table view!
*/
[tableController loadTable];
}
The Object Mapping is handled in this Class:
#implementation MMMappingProvider
#synthesize objectStore;
+ (id)mappingProviderWithObjectStore:(RKManagedObjectStore *)objectStore {
return [[self alloc] initWithObjectStore:objectStore];
}
- (id)initWithObjectStore:(RKManagedObjectStore *)theObjectStore {
self = [super init];
if (self) {
self.objectStore = theObjectStore;
[self setObjectMapping:[self requestObjectMapping] forResourcePathPattern:#"/requests" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMRequest fetchRequest];
return fetchRequest;
}];
[self setObjectMapping:[self answerObjectMapping] forResourcePathPattern:#"/requests/:request_id/answers" withFetchRequestBlock:^NSFetchRequest *(NSString *resourcePath) {
NSFetchRequest *fetchRequest = [MMAnswer fetchRequest];
fetchRequest.sortDescriptors = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"answer_id" ascending:YES]];
return fetchRequest;
}];
[self setSerializationMapping:[self.requestObjectMapping inverseMapping] forClass:[MMRequest class]];
[self setSerializationMapping:[self.answerObjectMapping inverseMapping] forClass:[MMAnswer class]];
[self setSerializationMapping:[self.userObjectMapping inverseMapping] forClass:[MMUser class]];
}
return self;
}
- (RKManagedObjectMapping *)userObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMUser" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"user_id";
[mapping mapAttributes:#"first_name", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"user_id",
nil];
return mapping;
}
- (RKManagedObjectMapping *)answerObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMAnswer" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"answer_id";
[mapping mapAttributes:#"text",#"request_id",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"answer_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
[mapping mapKeyPath:#"request" toRelationship:#"request" withMapping:[self requestObjectMapping]];
return mapping;
}
- (RKManagedObjectMapping *)requestObjectMapping {
RKManagedObjectMapping *mapping = [RKManagedObjectMapping mappingForEntityWithName:#"MMRequest" inManagedObjectStore:self.objectStore];
mapping.primaryKeyAttribute = #"request_id";
[mapping mapAttributes:#"title",#"user_id", nil];
[mapping mapKeyPathsToAttributes:
#"id", #"request_id",
nil];
[mapping mapKeyPath:#"user" toRelationship:#"user" withMapping:[self userObjectMapping]];
return mapping;
}
OK Figured it out!!! Some digging revealed that I was loading my UITableviewcontroller BEFORE the mapping provider.
The fix was, to take [self initialiserestkit] method in - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and put it before any of the code in this method (i.e. make [self initialiserestkit] the first line of the didfinishlaunchingwithoptions method.
Issue solved. Now the tableview is loaded AFTER the mappings so everything works as it should.
I created two CCLayers, one is gamelayer, another is howlayer. The code of gamelayer.m is
-(id)init{
if (self = [super init]) {
CCSprite *gamebg = [CCSprite spriteWithFile:#"bg.png"];
gamebg.anchorPoint = CGPointZero;
[self addChild:gamebg z:0 tag:1];
HowLayer *howLayer = [HowLayer node];
[self addChild:howLayer];
[self schedule:#selector(showthegamecontent:) interval:0.4];
}
return self;
}
the code of howlayer is
-(id)init{
if (self=[super init]) {
CCSprite *howbg = [CCSprite spriteWithFile:#"translucentbg.png"];
howbg.anchorPoint = CGPointZero;
[self addChild:howbg z:5 tag:1];
CCMenuItem *howmenu = [CCMenuItemImage itemFromNormalImage:#"how.png"
selectedImage:#"how.png"
target:self
selector:#selector(startgame:)];
CCMenu *ccMenuhowmenu = [CCMenu menuWithItems:howmenu, nil];
ccMenuhowmenu.position=ccp(517,384);
[self addChild:ccMenuhowmenu z:5 tag:2];
}
return self;
}
-(void)startgame:(id)sender{
[self removeAllChildrenWithCleanup:YES];
}
I want to do function like this:
When I click the menu on howlayer, the Howlayer will be removed (I have done), and then the game starts, calls the selector 'showthegamecontent', so how should I do?
Simple hack in your howlayer:
-(void)startgame:(id)sender{
gameLayer* parent = (gameLayer*) self.parent;
[parent showthegamecontent];
}
but it may leave you with a warning.. But it works..
The implementation without warning is that you have to store a reference to the parent with you init. Which i feel its unnecessary as you only need to reference it once.
I have a CCLayer class where I create an animated sprite that is the "hero" for the game. Now, I am trying to create multiple enemies for him to fight, and I'm having trouble. I want to create a class called "Enemy" that holds everything relevant to the enemy, and just create multiple instances of that class for all my enemies. How do I go about doing this?
Here's the class I have so far (where i create teh hero, called "_bear".
#import "FightGame.h"
#import "SneakyJoystick.h"
#import "SneakyJoystickSkinnedBase.h"
#import "ColoredCircleSprite.h"
#import "CCTouchDispatcher.h"
#import "GManager.h"
CCSprite *player;
BOOL _moving, _crouched, _jumping, _actionTouch, _maxJump, _leftJumping, _rightJumping, _punching, _kicking, _touchSet;
int startX, startY;
#implementation FightGame
#synthesize bear = _bear;
#synthesize jumpAction = _jumpAction;
#synthesize walkAction = _walkAction;
#synthesize punchAction = _punchAction;
#synthesize kickAction = _kickAction;
#synthesize crouchAction = _crouchAction;
#synthesize currentTouch;
+(id) scene
{
// 'scene' is an autorelease object.
CCScene *scene = [CCScene node];
// 'layer' is an autorelease object.
FightGame *layer = [FightGame node];
// add layer as a child to scene
[scene addChild: layer];
// return the scene
return scene;
}
// on "init" you need to initialize your instance
-(id) init
{
// always call "super" init
// Apple recommends to re-assign "self" with the "super" return value
if( (self=[super init] )) {
/*player = [CCSprite spriteWithFile: #"Person1.png"];
player.position = ccp( 50, 100 );
[self addChild:player]; */
//bools
_maxJump = FALSE;
_jumping = FALSE;
_leftJumping = FALSE;
_rightJumping = FALSE;
_touchSet = FALSE;
//Animated Bear
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"Fighter.plist"];
CCSpriteBatchNode *spriteSheet = [CCSpriteBatchNode
batchNodeWithFile:#"Fighter.png"];
[self addChild:spriteSheet];
//load frames
NSMutableArray *walkAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 6; ++i) {
[walkAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"walk%i.png", i]]];
}
NSMutableArray *punchAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 2; ++i) {
[punchAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"punch%i.png", i]]];
}
NSMutableArray *jumpAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 3; ++i) {
[jumpAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"jump%i.png", i]]];
}
NSMutableArray *kickAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 3; ++i) {
[kickAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"kick%i.png", i]]];
}
//create animation
CCAnimation *walkAnim = [CCAnimation
animationWithFrames:walkAnimFrames delay:0.1f];
CCAnimation *punchAnim = [CCAnimation
animationWithFrames:punchAnimFrames delay:0.1f];
CCAnimation *jumpAnim = [CCAnimation
animationWithFrames:jumpAnimFrames delay:0.5f];
CCAnimation *kickAnim = [CCAnimation
animationWithFrames:kickAnimFrames delay:0.1f];
CGSize winSize = [CCDirector sharedDirector].winSize;
self.bear = [CCSprite spriteWithSpriteFrameName:#"walk1.png"];
_bear.position = ccp(winSize.width/2, winSize.height/2);
//creating the actions
self.walkAction = [CCRepeatForever actionWithAction:
[CCAnimate actionWithAnimation:walkAnim restoreOriginalFrame:NO]];
self.punchAction = [CCRepeat actionWithAction:[CCAnimate actionWithAnimation:punchAnim] times:1];
self.jumpAction = [CCRepeat actionWithAction:[CCAnimate actionWithAnimation:jumpAnim] times:1];
self.kickAction = [CCRepeat actionWithAction:[CCAnimate actionWithAnimation:kickAnim] times:1];
[spriteSheet addChild:_bear];
//end animated bear, start joystick
SneakyJoystickSkinnedBase *leftJoy = [[[SneakyJoystickSkinnedBase alloc] init] autorelease];
leftJoy.position = ccp(60,60);
leftJoy.backgroundSprite = [ColoredCircleSprite circleWithColor:ccc4(105, 105, 105, 200) radius:55];
leftJoy.thumbSprite = [ColoredCircleSprite circleWithColor:ccc4(255, 0, 0, 200) radius:25];
leftJoy.joystick = [[SneakyJoystick alloc] initWithRect:CGRectMake(0,0,128,128)];
leftJoystick = [leftJoy.joystick retain];
[self addChild:leftJoy];
[self schedule:#selector(nextFrame:)];
self.isTouchEnabled = YES;
}
return self;
}
I could just give you the answer on this but that is useless. You need to crawl before you can run. Go to RayWenderlich.com and do at least some of his Cocos2D tutorials. You will get yourself up to speed quickly enough.