1

所以我正在使用 cocos2d 框架开发一款 iPad 游戏。

我的游戏需要在“关卡”开始时生成不同的建筑物。用户可以选择他们想要使用的建筑物。

这里的一个重要功能是不同的建筑物在按下时会执行不同的操作。

我有一个看起来像这样的父类:

BaseBuilding.h

@interface BaseBuilding : NSObject {
    CGRect _hitBox;
    NSString *_name;

    CCSprite *_sprite;
    int _identifier;
    int _health;

    int _coolDownDuration;
}

@property (atomic, retain) CCSprite *sprite;
@property (atomic, assign) int identifier;
@property (atomic, assign) int health;

- (void) onBuildingPressed;
- (id) initWithName:(NSString*)baseName;
- (id) initBuilding;
- (CGRect) hitBox;
- (void) sustainDamage;

所以我的大部分建筑都非常相似。每个建筑物都有自己的 initBuilding 方法,该方法会覆盖父级。initBuilding 方法调用该super initWithName方法,该方法然后查找包含有关该建筑物的信息(精灵名称等)的 plist。

每个建筑物也有自己的 onBuildingPressed 方法,该方法也覆盖了父方法。这是非常重要的功能。

我遇到问题的部分:

我想根据玩家选择的内容生成建筑物。我目前正在做的是这样的:

BaseBuilding *building;

switch (choice) {
    case 1:
        building = [BuildingX alloc];
        [building initBuilding];
        break;
    case 2:
        building = [BuildingY alloc];
        [building initBuilding];
        break;
    case 3:
        building = [BuildingZ alloc];
        [building initBuilding];
        break;
}

return building;

由于 BuildingX、BuildingY、BuildingZ 都是 BaseBuilding 的子类,因此 initBuilding 确实调用了正确的方法。

稍后我可以打电话[rightBuilding onBuildingPressed];,它按预期工作。

BuildingX 有一个其他建筑物没有的 removeAmmo 方法,所以我必须这样做才能调用它:[(BuildingX*)centerBuilding removeAmmo].

这是正确的,还是更好的方法?

4

4 回答 4

1

我唯一注意到的是,如果你有很多子类——假设所有子类都有一些字母顺序——你可以通过根据选择的值获取一个类对象来更快、更优雅地做到这一点:

NSString* className= [NSString stringWithFormat: @"Building%c",'X'-1+choice];
Class class= NSClassFromString(className);
BaseBuilding* building= [[class alloc] initBuilding];

但这只是风格和速度的问题(我的意思是编写代码)。你的方法很好,没有任何问题。

于 2013-08-17T17:24:21.417 回答
1

您可以在运行时验证该类,以保证这里没有出错的余地,如下所示:

if ( [centerBuilding respondsToSelector:NSSelectorFromString(@"removeAmmo")] ) {
    [centerBuilding performSelector:NSSelectorFromString(@"removeAmmo"];
}
于 2013-08-17T17:24:34.250 回答
0

对我来说似乎合乎逻辑。我不知道它是否时尚,势利小人可以为您确定。如果它有效,它就有效。我看不出修复没有损坏的东西有什么意义。

于 2013-08-17T17:12:09.903 回答
0

是的,这是正确的。但:

1)如果您将所有子类转换为父类,并且您需要使用子类的特定方法,那么仅在某些情况下才将其转换为正确的子类。尝试使 removeAmmo 成为基本方法...

或者

2) 让您的建筑子类从其内部调用 removeAmmo 方法,并在类别中声明 removeAmmo 方法

从外部的角度来看,BaseClass 没有 removeAmmo 方法,因此声明一个公共方法是不符合逻辑的,该方法只能被调用,只能将您的对象重新转换为特定的子类。

于 2013-08-17T17:18:40.273 回答