i'm working on some sample game using cocos2d to get more practise and I have a problem with classes. Here's my example:
someShapes.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface palleteOfShapes : CCLayer
{
NSMutableArray *shapesArray;
}
#property (nonatomic,retain) NSMutableArray *shapesArray;
-(void)drawPallete;
#end
someShapes.m
#import "palleteOfShapes.h"
#implementation palleteOfShapes
#synthesize shapesArray;
-(void)drawPallete
{
shapesArray = [NSMutableArray arrayWithObjects:#"Icon.png",#"A.png",#"questionMark.png",nil];
for (int i=0; i<shapesArray.count; i++) {
NSString *imagestring = [shapesArray objectAtIndex:i];
CCSprite *sprite = [CCSprite spriteWithFile:imagestring];
NSLog(#"i value: %i",i);
sprite.position=ccp(100*i,350);
NSLog(#"image added:%#",imagestring);
[self addChild:sprite];
NSLog(#"count: %d",[shapesArray count]);
}
NSLog(#"pallete was completed");
[shapesArray removeLastObject];
NSLog(#"count:%d",[shapesArray count]);
}
#end
in the main layer I do:
palleteOfShapes *newPallete = [[palleteOfShapes alloc]init];
[newPallete drawPallete];
I expected that these sprites will appear on my main layer, but they don't.
NSLog shows all messages but no sprites.
So if you can, please tell me what's wrong.
thanks in advance.
You add sprites to "palleteOfShapes" layer, but you never add them or "palleteOfShapes" to main layer.
Implement -(id) init method and try some initialisation there.
Related
I'm trying to make an app and I am currently trying to separate data into different files.
I will give some code from the main class (ArcherClass) and the player class.
This is the player class:
Player.h______________________
#interface Player:CCLayer{
CCSprite *_head;
}
#property (nonatomic, retain) CCSprite *head;
-(void)setHead:(CCSprite *)head;
+(id)player;
#end
Player.m______________________
#implementation Player
#synthesize head = _head;
+(id)player{
Player *playerSprite = nil;
return playerSprite;
}
-(void)setHead:(CCSprite *)head{
_head = [CCSprite spriteWithFile:#"head.png"];
}
#end
ArcherClass.m______________________
#import "ArcherClass.h"
#import "cocos2d.h"
#import "Player.h"
#implementation ArcherClass
//skip some stuff...
+(id) scene{
CCScene *scene = [CCscene node];
CCLayer* layer = [ArcherClass node];
[scene addChild:layer];
return scene;
}
-(id) init{
if(self = [super init]{
self.isTouchEnabled = YES;
}
Player *player = [[Player alloc]init];
CCSprite *bob = player.head;
bob.position = ccp(250,250);
//There are layers in this class, so this may be a problem
}
I had the app up and working, everything worked previously because everything was local to the ArcherClass. There were no other classes. Now I am trying to make seperate classes for everything, but I am running into problems. How can I fix this?
I started experimenting with Cocos2D with Tiled, and had the player sprite and actions coded within a CCLayer along with everything else. Before continuing on, I wanted to subclass the player into a CCLayer, which I hope is correct.
My header and main code is as follows:
HeroClass.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#interface HeroClass : CCLayer {
CCSprite *_hero;
CCAction *_heroSpriteFlyAction;
}
#property(nonatomic, retain) CCSprite *hero;
#property(nonatomic, retain) CCAction *heroSpriteFlyAction;
#end
HeroClass.m
#import "HeroClass.h"
#implementation HeroClass
#synthesize hero =_hero;
#synthesize heroSpriteFlyAction = _heroSpriteFlyAction;
-(id) init{
self = [super init];
if (!self) {
return nil;
}
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"heroTestSheet.plist"];
CCSpriteBatchNode *heroSpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"heroTestSheet.png"];
[self addChild:heroSpriteSheet];
NSMutableArray *heroSpriteFlyAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 2; ++i) {
[heroSpriteFlyAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"heroFrame%d.png", i]]];
}
CCAnimation *heroSpriteFlyAnim = [CCAnimation animationWithFrames:heroSpriteFlyAnimFrames delay:0.03f];
self = [CCSprite spriteWithSpriteFrameName:#"heroFrame1.png"];
_heroSpriteFlyAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:heroSpriteFlyAnim restoreOriginalFrame:NO]];
[self runAction:_heroSpriteFlyAction];
[heroSpriteSheet addChild:self];
return self;
}
- (void) dealloc{
self.hero = nil;
self.heroSpriteFlyAction = nil;
[super dealloc];
}
#end
I think the idea I want to achieve is that I can access things in this class as properties in other files. The code above gives no errors when I build it, but maybe I didn't do something right. The problem I'm having with the migration is what is happening now in my CCLayer class DebugZoneLayer, which creates the map and is supposed to add my player sprite but is giving me errors.
In DebugZoneLayer.h I imported the HeroClass.h and made a pointer from the HeroClass of the hero sprite and gave it a property. No errors here but it may be the start of where I'm going wrong:
#import "cocos2d.h"
#import "HeroClass.h"
#class HeroClass;
// DebugZone Layer
#interface DebugZoneLayer : CCLayer {
HeroControl *heroControl;
HeroClass *hero;
CCTMXTiledMap *theMap;
CCTMXLayer *blocksCollidable;
CCTMXLayer *invisiblePropertiesLayer;
}
#property(nonatomic, retain) CCSprite *hero;
In DebugZoneLayer.m, when I synthesize hero, it gives the error "Type of property 'hero' does not match type of ivar 'hero'
#synthesize hero;
The rest of the file gives me more errors related to anything referencing hero, but at least that's where it starts.
EDIT (updated)
Just wanted to mention, since this was solved I cleared up some major issues in HeroClass.m which was causing a crash:
#import "HeroClass.h"
#implementation HeroClass
#synthesize heroSprite =_heroSprite;
#synthesize heroSpriteSheet =_heroSpriteSheet;
#synthesize heroSpriteFlyAction = _heroSpriteFlyAction;
-(id) init{
self = [super init];
if (!self) {
return nil;
}
[[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:#"heroTestSheet.plist"];
_heroSpriteSheet = [CCSpriteBatchNode batchNodeWithFile:#"heroTestSheet.png"];
//[self addChild:_heroSpriteSheet];
NSMutableArray *heroSpriteFlyAnimFrames = [NSMutableArray array];
for(int i = 1; i <= 2; ++i) {
[heroSpriteFlyAnimFrames addObject:
[[CCSpriteFrameCache sharedSpriteFrameCache] spriteFrameByName:
[NSString stringWithFormat:#"heroFrame%d.png", i]]];
}
CCAnimation *heroSpriteFlyAnim = [CCAnimation animationWithFrames:heroSpriteFlyAnimFrames delay:0.03f];
_heroSprite = [CCSprite spriteWithSpriteFrameName:#"heroFrame1.png"];
_heroSpriteFlyAction = [CCRepeatForever actionWithAction:[CCAnimate actionWithAnimation:heroSpriteFlyAnim restoreOriginalFrame:NO]];
[self runAction:_heroSpriteFlyAction];
[_heroSpriteSheet addChild:_heroSprite];
return self;
}
- (void) dealloc{
self.heroSprite = nil;
self.heroSpriteSheet = nil;
self.heroSpriteFlyAction = nil;
[super dealloc];
}
#end
This is not 100% related to your problem .. but you have another issues with your properties.
You define your property as retain, and you release it in the dealloc function, but actually you never retain the object.
_heroSprite = [CCSprite spriteWithSpriteFrameName:#"heroFrame1.png"];
at this position the _heroSprite variable contains the sprite with autorelease enabled... you don't retain it.
Of course you don't loose it, because it will get retained by this line:
[heroSpriteSheet addChild:_heroSprite];
but it will get released when the child is removed from the sheet.
so this is unnecessary in dealloc: self.heroSprite = nil; and [_heroSprite release]; would even crash your code.
As said before, the code works, but when you look over it later, you might get confused.
You should declare the proberty as (nonatomic, assign) or retain it properly with
self.herosprite = [CCSprite spriteWithSpriteFrameName:#"heroFrame1.png"];
Trying changing your property in the DebugZoneLayer class from:
#property(nonatomic, retain) CCSprite *hero;
To:
#property(nonatomic, retain) HeroClass *hero;
Just wondered if someone could quickly give me a hand. Im building a simple puzzle slider game, ive added a timer to the game now and all i want to do is pass the time it took to complete the puzzle over to the congrats scene. Could anyone just have a look at my code see where im going wrong please?
play.h
#import "cocos2d.h"
#import "Box.h"
#interface PlayLayer : CCLayer
{
int timeInt;
int secs;
int mins;
CCLabel *timeLabel;
NSString *TotalTimeString;
}
#property (nonatomic, assign) int timeInt;
#property (nonatomic, assign) int secs;
#property (nonatomic, assign) int mins;
#property (nonatomic, retain) NSString *TotalTimeString;
#end
Play.m
#import "PlayLayer.h"
#import "Congrats.h"
#implementation PlayLayer
#synthesize timeInt;
#synthesize secs;
#synthesize mins;
#synthesize TotalTimeString;
-(id) init{
self = [super init];
TotalTimeString = [NSString stringWithFormat:#"Time: %02d:%02d", mins, secs];
timeLabel = [[CCLabel labelWithString:TotalTimeString dimensions: CGSizeMake(130,27) alignment: UITextAlignmentCenter fontName:#"Marker Felt" fontSize:25.0] retain];
timeLabel.position = ccp(155,430);
[self addChild:timeLabel];
[self schedule: #selector(tick2:) interval:1.0];
return self;
}
-(void) tick2: (id) sender{
timeInt++;
secs = timeInt % 60;
mins = timeInt / 60;
[timeLabel setString: TotalTimeString];
}
-(void) check: (id) sender data: (id) data{
int valueToCheck = 0;
bool breakOut = false;
for (int y=0; y < box.size.height && !breakOut; y++) {
for (int x=0; x < box.size.width && !breakOut; x++) {
Tile *tile = [box objectAtX:x Y:y];
if (tile.check != [box hashOfXY:x y:y]) breakOut = true;
valueToCheck++;
}
}
int totalTiles = box.size.width * box.size.height;
if (valueToCheck == totalTiles){
[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:1 scene:[Congrats node]]];
CCScene *scene = [Congrats scene];
scene.TotalTimeTakenWhenDiedString = TotalTimeString;
[[CCDirector sharedDirector] replaceScene:scene];
}
}
#end
Congrats.h
#import <Foundation/Foundation.h>
#import "cocos2d.h"
#import "PlayLayer.h"
#interface Congrats : CCLayer {
CCLabel *timeLabel;
NSString *TotalTimeTakenWhenDiedString;
}
#property (nonatomic, assign) NSString *TotalTimeTakenWhenDiedString;
+(id) scene;
#end
Congrats.m
#import "Congrats.h"
#import "DifficultyLevel.h"
#import "PlayLayer.h"
#import "PlayLayerMedium.h"
#import "PlayLayerHard.h"
#import "MainMenu.h"
#implementation Congrats
#synthesize TotalTimeTakenWhenDiedString;
+(id) scene {
// ‘scene’ is an autorelease object.
CCScene *scene = [CCScene node];
// ‘layer’ is an autorelease object.
Congrats *layer = [Congrats 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] )) {
timeLabel = [[CCLabel labelWithString: TotalTimeTakenWhenDiedString dimensions: CGSizeMake(130,27) alignment: UITextAlignmentCenter fontName:#"Marker Felt" fontSize:25.0] retain];
timeLabel.position = ccp(155,430);
}
return self;
}
-(void) goToGameplay: (id) sender {
[[CCDirector sharedDirector] replaceScene:[CCFadeTransition transitionWithDuration:1 scene:[MainMenu node]]];
}
}
#end
I was kind of hoping that, that would work. But i keep getting this error "error: request for member 'TotalTimeTakenWhenDiedString' in something not a structure or union"
Anyone help at all?
Cheers
Your problem is here:
CCScene *scene = [Congrats scene];
scene.TotalTimeTakenWhenDiedString = TotalTimeString;
The object scene is of type CCScene and you are trying to access TotalTimeTakenWhenDiedString on it. But that is a property of Congrats, not of CCScene.
Here's a suggestion which might work, by getting the Congrats object out from scene. (Caveat: I'm not familiar with cocos2d, and I only looked it up quickly here. This may be a terrible way to be doing it!)
Change here:
// add layer as a child to scene
[scene addChild:layer z:0 tag:1]; // tag it with 1
and here:
CCScene *scene = [Congrats scene];
Congrats *congrats = (Congrats *)[scene getChildByTag:1]; // get the congrats child object, which we tagged 1
congrats.TotalTimeTakenWhenDiedString = TotalTimeString;
[[CCDirector sharedDirector] replaceScene:scene];
... Why dont you just create a singleton class which you can use as a global object? and access/update it anywhere in the game?
everyone!
I have tested this simplest code as following:
StorePin.h
#import <Foundation/Foundation.h>
#import <MAPKIT/mapkit.h>
#import <CORELOCATION/corelocation.h>
#interface StorePin : NSObject <MKAnnotation> {
CLLocationCoordinate2D coordinate;
NSString *subtitle;
NSString *title;
}
#property (nonatomic,assign) CLLocationCoordinate2D coordinate;
#property (nonatomic,retain) NSString *subtitle;
#property (nonatomic,retain) NSString *title;
-(id) initWithCoords:(CLLocationCoordinate2D) coords;
#end
StorePin.m
#import "StorePin.h"
#implementation StorePin
#synthesize coordinate, subtitle, title;
- (id) initWithCoords:(CLLocationCoordinate2D) coords{
self = [super init];
if (self != nil) {
coordinate = coords;
}
return self;
}
- (void) dealloc
{
[title release];
[subtitle release];
[super dealloc];
}
#end
In my ViewControlller, I made a button to add and remove annotations repeatly.
#import "mapViewTestViewController.h"
#import "StorePin.h"
#implementation mapViewTestViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (IBAction)refresh
{
[mapView removeAnnotations:mapView.annotations];
for (int i = 0; i < 101; i ++)
{
CLLocationCoordinate2D p1;
p1.latitude = i/10.0;
p1.longitude = i/10.0;
StorePin *poi = [[StorePin alloc] initWithCoords:p1];
[mapView addAnnotation:poi];
[poi release];
}
}
- (void)dealloc
{
[super dealloc];
}
#end
If I loop less than 100 times to add and remove annotations, all work normally. But if I loop more than 100 times, it will cause memory leak once. I'm nearly crazy to this strange problem. Is this my code's bug or mkmapview's bug? Thank you for helping me.
You don't say what objects have been detected as leaking, but if they are StorePins, then it's MapKit's problem -- your memory management code for the StorePins you create in the loop is just fine.
One thing that you do that might be causing MapKit trouble is passing the map view a reference to its own ivar that you want it to modify. It doesn't seem too likely -- if it was really a problem, it would probably cause a crash rather than a leak. However, you might try making a copy, either shallow (as Kai wrote earlier, but absolutely do not follow the advice about using retain counts and calling release in a loop):
NSArray * annotationsCopy = [NSArray arrayWithArray:mapView.annotations];
or deep:
NSArray * annotationsDeepCopy = [[[NSArray alloc] initWithArray:mapView.annotations
copyItems:YES]
autorelease];
then pass the copy to removeAnnotations:.
The second option creates an autoreleased array with a copy of every item in the annotations list so that the map view doesn't try to remove the same instances that it's iterating over. Obviously this uses twice the memory; you probably only want to bother with this for bug-hunting.
If it fixes the leak, great, if not, then there's probably nothing you can do about it.
In case you don't want to remove the user's location blue dot on the map, you can use:
NSArray * annotationsCopy = [NSArray arrayWithArray:[mapView.annotations filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:#"!(self isKindOfClass: %#)", [MKUserLocation class]]]];
Im trying to add an animation of a monkey using a NSMutablAarray of UIImageViews. Im following a tutorial on youtube but when i compile i get a strange error: "stray '\357' in program." on the line "UIImage *img = [UIImage imageName: pictureName];"
Here are my h and m files..
#import "WinGameView.h"
#implementation WinGameView
#synthesize monkeyAnimation;
#synthesize monkeyImages;
-(IBAction)pushBack{
[self dismissModalViewControllerAnimated:YES];
}
// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {
monkeyImages = [[NSMutableArray alloc] init];
for(int i = 1; i < 10; i++)
{
NSString *pictureName = [NSString stringWithFormat:#"monkey%d.gif",i];
UIImage *img = [UIImage imageName: pictureName];
if (img) [monkeyImages addObject:img];
}
[monkeyAnimation setAnimationImages:monkeyImages];
[monkeyAnimation setAnimationDuration:1.2f];
[monkeyAnimation startAnimating];
[super viewDidLoad];
}
and
#import <UIKit/UIKit.h>
#interface WinGameView : UIViewController {
IBOutlet UILabel *labelWin;
IBOutlet UILabel *labelWin2;
IBOutlet UIButton *buttonBack;
IBOutlet UIImageView *monkeyAnimation;
NSMutableArray *monkeyImages;
}
#property(nonatomic,retain)UIImageView *monkeyAnimation;
#property(nonatomic, retain)NSMutableArray *monkeyImages;
-(IBAction)pushBack;
#end
Does anyone know what i am doing wrong or why i am getting these wierd message. I have tried to look it up online but to no avail.
There is a stray "byte order mark" on that line (or even the line above or below). Retype the inside of the for loop by hand.