首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >游戏世界工厂级

游戏世界工厂级
EN

Code Review用户
提问于 2014-09-12 14:42:11
回答 1查看 127关注 0票数 3

世界在我的战略游戏是由许多塔组成。在游戏开始时,只生成一个塔,当玩家发现新的塔时,他们被创建并添加到游戏控制的塔阵列中。塔楼后的第一个塔楼以不同的设置开始。例如,他们不从工人和动物开始,不同的楼层显示和配置。

以前,我在Tower类的初始化过程中使用了所有这些代码。这个类有太多的责任,并且增加到超过1200行,所以我一直在寻找方法来重构它,以尽可能多地删除代码,这样就更容易理解了。为了实现这个目标,我创建了一个工厂类来创建一个塔。游戏调用工厂类的类方法,并得到一个完全配置的塔作为回报。这使塔类减少了近200行。

这是我第一次创建一个工厂类,我认为我的实现肯定需要一些反馈。我决定使用一个类方法,这样我就不需要这个工厂类的实际实例来创建这些塔了。其结果是,我需要在工厂类中使用C函数。其他选项是创建一个类似于normal的类,并在游戏开始时创建一个工厂类的实例。另一种选择是创建一个单例,以获得类似于类方法的语法,同时也具有拥有实例方法的能力。

我应该指出,worldSize到处传播的原因是为了确保游戏与不同的屏幕分辨率兼容。

我对代码的所有方面都持批评态度,但最重要的是这是否是一个工厂类的良好实现。

标头只包含类方法,所以我将省略它。

DTTowerFactory.m

代码语言:javascript
复制
#import "DTAnimal.h"
#import "DTDwarf.h"
#import "DTTower.h"
#import "DTTowerFactory.h"
#import "DTTowerFloor.h"

@implementation DTTowerFactory

+(DTTower *) towerWithWorldSize:(CGSize)worldSize isFirstTower:(BOOL)isFirstTower {
    DTTower *tower = [[DTTower alloc]initWithWorldSize:worldSize];

    if (isFirstTower) {
        createTowerFloors(tower, worldSize);
        setBackgroundTypes(tower);
        setupInitialTowerFloors(tower);
        createTowerDwarves(tower, worldSize);
        createTowerAnimals(tower, worldSize);
    } else {
        createTowerFloors(tower, worldSize);
        setBackgroundTypes(tower);
        setupTowerFloors(tower);
    }

    return tower;
}

#pragma mark - Tower Defaults
void createTowerFloors(DTTower* tower, CGSize worldSize) {

    int topFloor = 10; // later this will be influenced by a gravity setting
    //a random number of floors underground, not less than 90
    int randomBottomFloor = arc4random_uniform(31) + 90;
    int bottomFloor = -randomBottomFloor;

    //create the floors and set them all to dirt to start
    for (int i = bottomFloor; i <= topFloor; i++) {
        NSNumber *floorNumber = [NSNumber numberWithInteger:i];
        DTTowerFloor *floor = [[DTTowerFloor alloc]initWithType:Dirt andFloor:i andWorldSize:worldSize];
        [tower.towerDict setObject:floor forKey:floorNumber];
    }

    //the top floors do not have ground or blocks for mining
    for (int i = topFloor; i >= 0; i--) {
        NSNumber *floorNumber = [NSNumber numberWithInt:i];
        DTTowerFloor *floor = [tower.towerDict objectForKey:floorNumber];
        [floor.groundBlocks removeAllObjects];
        floor.groundType = NoGround;
    }

    //randomly determine where the different ground types start
    int randomStartingDirtRockFloor = (arc4random_uniform(15) + 15);
    int randomStartingRockFloor = (arc4random_uniform(30) + randomStartingDirtRockFloor);
    int randomStartingRockLavaFloor = (arc4random_uniform(30) + randomStartingRockFloor);
    //have to make them all negative inside these loops
    for (int i = -randomStartingDirtRockFloor; i > -randomStartingRockFloor; i--) {
        NSNumber *floorNumber = [NSNumber numberWithInt:i];
        DTTowerFloor *floor = [tower.towerDict objectForKey:floorNumber];
        floor.groundType = DirtRock;
    }
    for (int i = -randomStartingRockFloor; i > -randomStartingRockLavaFloor; i--) {
        NSNumber *floorNumber = [NSNumber numberWithInt:i];
        DTTowerFloor *floor = [tower.towerDict objectForKey:floorNumber];
        floor.groundType = Rock;
    }
    for (int i = -randomStartingRockLavaFloor; i > bottomFloor; i--) {
        NSNumber *floorNumber = [NSNumber numberWithInt:i];
        DTTowerFloor *floor = [tower.towerDict objectForKey:floorNumber];
        floor.groundType = RockLava;
    }
}
void setBackgroundTypes(DTTower* tower) {
    for (id key in tower.towerDict) {
        DTTowerFloor *floor = [tower.towerDict objectForKey:key];

        //could use this later to have a weighted average
        //int floorNumber = floor.floorNumber;
        //int backgroundType;

        //but for now it will be a simple range
        int randomNumber = arc4random_uniform(80);
        //int randomNumber = skRand(0, 80);

        if (randomNumber < 10) {
            floor.backgroundType = 0;
        } else if (randomNumber >= 10 && randomNumber < 20) {
            floor.backgroundType = 1;
        } else if (randomNumber >= 20 && randomNumber < 30) {
            floor.backgroundType = 2;
        } else if (randomNumber >= 30 && randomNumber < 40) {
            floor.backgroundType = 3;
        } else if (randomNumber >= 40 && randomNumber < 50) {
            floor.backgroundType = 4;
        } else if (randomNumber >= 50 && randomNumber < 60) {
            floor.backgroundType = 5;
        } else if (randomNumber >= 60 && randomNumber < 70) {
            floor.backgroundType = 6;
        } else if (randomNumber >= 70 && randomNumber < 80) {
            floor.backgroundType = 7;
        }
    }
}

#pragma mark - First Tower
void setupInitialTowerFloors(DTTower* tower) {
    for (int i = 0; i > -4; i--) {
        NSNumber *floorNumber = [NSNumber numberWithInt:i];
        DTTowerFloor *floor = [tower.towerDict objectForKey:floorNumber];
        floor.isRevealed = YES;
        //adds ladders here for convenience
        floor.floorBuildState |= FloorHasLadder;
    }
    //have to do three floors manually for the top and bottom and floor 0
    NSNumber *floorNumber0 = [NSNumber numberWithInt:0];
    DTTowerFloor *tempFloor0 = [tower.towerDict objectForKey:floorNumber0];
    tempFloor0.floorBuildState |= FloorHasWalls | FloorHasBottom | FloorHasRoom;
    NSNumber *floorNumber1 = [NSNumber numberWithInt:1];
    DTTowerFloor *tempFloor1 = [tower.towerDict objectForKey:floorNumber1];
    tempFloor1.isRevealed = YES;
    tempFloor1.floorBuildState |= FloorHasBottom;
    NSNumber *floorNumber2 = [NSNumber numberWithInt:-4];
    DTTowerFloor *tempFloor2 = [tower.towerDict objectForKey:floorNumber2];
    tempFloor2.isRevealed = YES;
}
void createTowerDwarves(DTTower* tower, CGSize worldSize) {
    int numStartingDwarves = 5;
    for (int i = 0; i < numStartingDwarves; i++){
        DTDwarf *newDwarf = startingDwarf(worldSize);
        [tower.towerDwarves addObject:newDwarf];
        [tower.dwarfListForRender addObject:newDwarf];
    }
}
DTDwarf* startingDwarf(CGSize worldSize) {
    DTDwarf *dwarf = [[DTDwarf alloc]initWithWorldSize:worldSize];
    dwarf.dwarfMovement.currentFloor = -1;
    dwarf.dwarfMovement.destinationFloor = dwarf.dwarfMovement.currentFloor;
    dwarf.dwarfMovement.currentPosition = CGPointMake(0, dwarf.dwarfMovement.currentFloor * worldSize.height/6 - worldSize.height/6/3);
    return dwarf;
}
void createTowerAnimals(DTTower* tower, CGSize worldSize) {
    DTTowerFloor *floor = [tower.towerDict objectForKey:[NSNumber numberWithInt:0]];
    int numStartingAnimals = 3;
    for (int i = 0; i < numStartingAnimals; i++) {
        [floor acceptAnimal:startingAnimal(worldSize)];
    }
}
DTAnimal* startingAnimal(CGSize worldSize) {
    int randomNumber = arc4random_uniform(3);
    DTAnimal *animal = [[DTAnimal alloc]initWithAnimalType:randomNumber andWorldSize:worldSize];
    return animal;
}

#pragma mark - Additional Towers
void setupTowerFloors(DTTower* tower) {
    int startingFloorOffset = -51;
    int randomNumber = arc4random_uniform(25);
    int startingFloorInt = startingFloorOffset + randomNumber;
    int oneFloorAboveInt = startingFloorInt + 1;
    int oneFloorBelowInt = startingFloorInt - 1;

    [tower assignStartingFloorForNewTower:startingFloorInt];

    NSNumber *startFloorNum = [NSNumber numberWithInt:startingFloorInt];
    DTTowerFloor *startFloor = [tower.towerDict objectForKey:startFloorNum];
    [startFloor.groundBlocks removeAllObjects];
    startFloor.isRevealed = YES;

    startFloor.floorBuildState |= FloorHasLadder | FloorHasWalls | FloorHasBottom | FloorHasRoom | FloorHasRoomUpgrade;

    [startFloor buildRoomUpgrade:RoomTypeGatewayExit];

    NSNumber *oneFloorAboveNum = [NSNumber numberWithInt:oneFloorAboveInt];
    DTTowerFloor *oneFloorAbove = [tower.towerDict objectForKey:oneFloorAboveNum];
    oneFloorAbove.isRevealed = YES;

    NSNumber *oneFloorBelowNum = [NSNumber numberWithInt:oneFloorBelowInt];
    DTTowerFloor *oneFloorBelow = [tower.towerDict objectForKey:oneFloorBelowNum];
    oneFloorBelow.isRevealed = YES;
}

@end

这里是塔的初始化,我将包括它,因为这个方法调用它开始创建塔。这里包括实例变量和属性。我本可以在工厂类中初始化这些属性,但为了简单起见,我将它们留在这里。我不知道这是否正确的选择。

DTTower.m

代码语言:javascript
复制
-(id) initWithWorldSize:(CGSize)worldSize {
    self = [super init];
    if (self){
        _worldSize = worldSize;

        _towerDict = [[NSMutableDictionary alloc]init];

        _balanceSettings = [[DTGameBalance alloc]init];

        _completedJobs = [[NSMutableArray alloc]init];
        _resourcesForCollection = [[NSMutableArray alloc]init];
        _dwarvesForGamePickup = [[NSMutableArray alloc]init];

        _startingFloorForNewTower = 0;

        _towerEnemies = [[NSMutableArray alloc]init];
        _towerDwarves = [[NSMutableArray alloc]init];
        _towerAnimals = [[NSMutableArray alloc]init];

        _deadDwarfStatsForPickup = [[NSMutableArray alloc]init];

        _dwarfListForRender = [[NSMutableArray alloc]init];
    }
    return self;
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2014-09-13 00:50:18

我认为工厂班是完全没有必要的。我也不明白你是如何从一个文件中节省200行的。

在我看来,DTTowerFactory.m中的代码来自几个不同的文件(可能需要返回到这些文件)。

towerWithWorldSize:isFirstTower属于DTTower.m

createTowerFloors()应该返回一个NSDictionary对象,并且属于DTTowerFloor.m。你应该做的是:

代码语言:javascript
复制
someTower.towerDict = createTowerFloor(worldSize);

setBackgroundTypes()可能只是createTowerFloors()函数的一部分。在创建地板时,有什么原因不能设置地板的背景类型吗?

setupInitialTowerFloors()setupTowerFloors()又可能成为DTTowerFloor.m的一部分,就像createTowerFloors()一样。

startingDwarf()createTowerDwarves可以移动到DTDwarf.m中。

startingAnimal()createTowerAnimals()可以移动到DTAnimal.m中。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/62755

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档