HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Worker AI and Job Queue Management for Simulation Game

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
simulationworkermanagementgameforandqueuejob

Problem

So I've been working on AI for a Tower Building simulation game for quite a few days, and I think the code would really benefit from review. I'm a hobbyist programmer, but I really care about doing things properly so don't be afraid to be harsh. I want to learn.

The basic idea of the job management system is as follows. The user chooses a job with touch commands in the scene. The game evaluates if the job is valid, and if there are enough resources to perform the job. If so, it passes the job to the tower, which passes the job to the appropriate tower floor object.

The dwarves are held in an array by the tower. Each tick, it passes each dwarf an array of floors that contain jobs. The AI of the dwarf chooses which floor to travel to based on its current state, whether all the job slots are full on the floor, and it always moves to the closest floor with available jobs.

When it gets to the floor, the tower passes the dwarf to the floor object. The floor object then tells the dwarf where the position of the job is, and fills one of the active job slots until there are none remaining. When the dwarf reaches the position of the job, the floor sets it to working, and collects the completed job when it is finished. It then tells the dwarf to move to the exit of the floor. The dwarves only move left, right, up and down.

Here is the code.

First the character object, which the dwarves inherit from.

DTCharacter.h:

#import 

@interface DTCharacter : NSObject

//need the world size for proper positioning
@property CGSize worldSize;

@property CGPoint currentPosition;
@property CGPoint destinationPosition;
@property int currentFloor;
@property int destinationFloor;

-(void) moveUp;
-(void) moveDown;
-(void) moveLeft;
-(void) moveRight;

//only used by animals now
@property BOOL isIdle;

@end


DTCharacter.m:

```
#import "DTCharacter.h"

@implementation DTCharacter

#pragma mark - Movement
-(void) moveUp {
self.currentPosition = CGPointMake(0, self.cu

Solution

I think that DTCharacter object shouldn't know about the world size. You should create some DTWorld class and DTCharacter object should be added to this world. DTCharacter should have and reference to the world and should asking if there is possibility to make a move in specified direction. Maybe good way is to create world as singleton because it's only one. E.g.:

-(void) moveUp {
    CGPoint destination = ...;
    BOOL canMove = [[DTWorld sharedInstance] canMoveToPoint:destination];
    if (canMove) {
        self.currentPosition = destination;
    }
}


Also this is not a good way:

self.currentPosition.y + self.worldSize.height / 18)


Make it like this:

static NSInteger const kStep = 18;
@implementation
...


And in code:

self.currentPosition.y + kStep;


DTDwarf
Method -checkStatus should be called update because there is a more things done.

DTTowerFloor
Properties as following should be define as (readonly).

@property BOOL hasWalls;
@property BOOL hasBottom;
@property BOOL hasLadder;
@property BOOL hasRoom;
@property BOOL hasRoomUpgrade;


Should be like this:

@property (nonatomic, readonly, getter = hasWalls) BOOL walls;
@property (nonatomic, readonly, getter = hasBottom) BOOL bottom;
...


That's all for now. General rule, try to make your classes with SRP. It's good way to create some class diagram e.g. in Visual Paradigm to check if all looks good. I always start with UML-ing before coding something bigger. Also I think that DTTowerFloor is to clever and some responsibilities should be moved out of this class.

Also you should keep in mind that you should design your classes in the way that this classes expose as little as possible. It simplify class design.

Code Snippets

-(void) moveUp {
    CGPoint destination = ...;
    BOOL canMove = [[DTWorld sharedInstance] canMoveToPoint:destination];
    if (canMove) {
        self.currentPosition = destination;
    }
}
self.currentPosition.y + self.worldSize.height / 18)
static NSInteger const kStep = 18;
@implementation
...
self.currentPosition.y + kStep;
@property BOOL hasWalls;
@property BOOL hasBottom;
@property BOOL hasLadder;
@property BOOL hasRoom;
@property BOOL hasRoomUpgrade;

Context

StackExchange Code Review Q#49602, answer score: 5

Revisions (0)

No revisions yet.