我正在尝试通过构建一个简单的纸牌游戏来试验cocos2d。我不是iOS开发的新手,但我对cocos2d引擎很新。到目前为止,我有2个自定义类:
卡片类: .H
#import <Foundation/Foundation.h>
#import "cocos2d.h"
@interface Card : NSObject {
CCSprite *faceSprite;
NSString *suit;
NSUInteger value;
float priority;
}
@property (nonatomic, retain) CCSprite *faceSprite;
@property (nonatomic, readonly) NSString *suit;
@property (nonatomic, readonly) NSUInteger value;
@property (nonatomic, assign) float priority;
- (id)initWithSprite:(CCSprite *)paramSprite suit:(NSString *)paramSuit andValue:(NSUInteger)paramValue;
@end
的.m
#import "Card.h"
@implementation Card
@synthesize faceSprite, suit, value, priority;
- (id)init
{
self = [self initWithSprite:nil suit:nil andValue:nil];
if (self) {
// Initialization code here.
}
return self;
}
-(id)initWithSprite:(CCSprite *)paramSprite suit:(NSString *)paramSuit andValue:(NSUInteger)paramValue {
if ((self = [super init])) {
faceSprite = paramSprite;
suit = paramSuit;
value = paramValue;
}
return self;
}
@end
和甲板课: .H
#import <Foundation/Foundation.h>
#import "Card.h"
@interface Deck : NSObject {
NSMutableArray *cardsArray;
}
@property (nonatomic, retain) NSMutableArray *cardsArray;
-(void)shuffle;
-(Card *)drawTopCard;
@end
的.m
- (id)init
{
if ((self = [super init])) {
cardsArray = [[NSMutableArray alloc] init];
for (NSInteger suit = 1; suit < 5; suit++) {
NSString *suitString;
switch (suit) {
case 1:
suitString = @"h";
break;
case 2:
suitString = @"d";
break;
case 3:
suitString = @"s";
break;
case 4:
suitString = @"c";
break;
}
for (NSInteger i = 3; i < 14; i++) {
CCSprite *cardImage = [CCSprite spriteWithFile:[NSString stringWithFormat:@"%d%@.gif",i, suitString]];
Card *card = [[Card alloc] initWithSprite:cardImage suit:suitString andValue:i];
[cardsArray addObject:card];
}
}
}
return self;
}
-(void)shuffle {
int timesToShuffle = 1;
while (++timesToShuffle < 4) {
for (int i = 0; i < [cardsArray count]; i++) {
int cardToSwap = arc4random() % [cardsArray count];
[cardsArray exchangeObjectAtIndex:i withObjectAtIndex:cardToSwap];
}
}
}
-(Card *)drawTopCard {
Card *cardDrawn = [[cardsArray objectAtIndex:0] retain];
//[cardsArray removeObjectAtIndex:0];
return cardDrawn;
}
@end
当我尝试在主场景中执行以下操作时,我在更新中的CCScheduler.m中出现了EXC_BAD_ACCESS错误:(ccTime)方法
-(id) init
{
if( (self=[super init])) {
deck = [[Deck alloc] init];
[deck shuffle];
[self schedule:@selector(drawAndShowCard) interval:3.0];
}
return self;
}
-(void)drawAndShowCard {
// ask director the the window size
CGSize size = [[CCDirector sharedDirector] winSize];
// position the label on the center of the screen
Card *card = [deck drawTopCard];
CCSprite *cardSprite = (CCSprite *)card.faceSprite;
cardSprite.position = ccp( size.width /2 , size.height/2 );
[self addChild:cardSprite];
}
奇怪的是,如果我在drawCardAndShow方法中移动了deck alloc和shuffle,它就不会再崩溃了,但是由于出于明显的原因,这不是正确的地方,因为我不想每次都有一个全新的套牌我画了一张卡片......
任何帮助?
答案 0 :(得分:2)
我发现了一个严重的问题,但您的代码存在多个问题。
当你有字符串作为属性时,你应该将它们声明为副本,在你的情况下你将它作为赋值:
@property (nonatomic, readonly) NSString *suit;
如果要以只读方式声明属性,可以再次在.m中声明该属性,使其在内部可写:
@interface Card()
@property (nonatomic, copy)
NSString *suit;
@end
当您访问ivar和访问该属性时,您应该使用属性的self.
表示法让其他人明白您的意图。
你在这里遇到了一个漏洞:
Card *card = [[Card alloc] initWithSprite:cardImage suit:suitString andValue:i];
[cardsArray addObject:card];
-->missing [card release]
这是不必要的
@interface Deck : NSObject {
NSMutableArray *cardsArray;
}
@property (nonatomic, retain) NSMutableArray *cardsArray;
您可以省略ivar,只需确保在没有自动释放的情况下不分配/ init。
如果你坚持要将ivar重命名至少_cardsArray然后再
@synthesize cardsArray=_cardsArray
这样你就可以区分这两者了。在一种情况下,你需要明确保留,在另一种情况下你需要使用setter / getter。
HTH
答案 1 :(得分:1)
你应该将deck设为属性