I've been working a strategy game for iOS for a little while, and each time I add functionality to the game model I'm finding myself building a lot of UI code to sync up with it. I believe that my latest creation could use some code review.
The basic idea is that each worker can have certain job permissions turned on or off. The Scene grabs the worker array from the game and builds a window that will allow the user to enable or disable each type of job by ticking a set of boxes next to their name.
I needed to make it so that the list was always in the same order and so that dead workers would be removed from the list. If I grabbed a new, fresh array every time, the order of the list was changing. So I made an array inside the Scene, and I update it by adding a worker to the array only if it is not currently present. Once that is done, the dead workers are removed from the list. Then finally the UI is built with the edited array of workers.
I also needed to make it so that only a certain number of workers was displayed on each page, and that pages would be added once the number of workers passed that threshold.
Finally, I didn't want this list to be able to change while it was open, because it would be difficult to hit the checkboxes if they were able to move around. So when switching between pages, the contents of the worker array do not get updated.
-(void) buildDwarfJobPermissionBox:(int)pageNumber {
_dwarfJobPermissionBox = [[SKNode alloc]init];
[self addChild:_dwarfJobPermissionBox];
NSMutableArray *tempDwarfArray = [[NSMutableArray alloc]init];
//if the box is already open, use the existing array rather than build a new one
if (!_dwarfJobPermissionBoxIsOpen) {
tempDwarfArray = [_game getDwarvesForRender];
for (DTDwarf *dwarf in tempDwarfArray) {
if (![self isDwarfAlreadyInArray:dwarf]) {
[_dwarfArrayForStatusBox addObject:dwarf];
}
}
[self removeDeadDwarvesFromArray];
_dwarfJobPermissionBoxIsOpen = YES;
} else {
tempDwarfArray = _dwarfArrayForStatusBox;
}
int numDwarvesPerPage = 6;
int numPages = _dwarfArrayForStatusBox.count / numDwarvesPerPage;
if (numPages < 1) {
numPages = 1;
}
int positionInDwarfArray = 0;
NSMutableArray *arrayOfPages = [[NSMutableArray alloc]init];
for (int i = 0; i <= numPages; i++) {
NSMutableArray *page = [[NSMutableArray alloc]init];
for (int j = 0; j < numDwarvesPerPage; j++) {
//stop adding dwarves to the list once at the end of the array
if (positionInDwarfArray > _dwarfArrayForStatusBox.count - 1) {
//set it to this value to easily break the outer loop
j = numDwarvesPerPage;
break;
} else {
[page addObject:[_dwarfArrayForStatusBox objectAtIndex:positionInDwarfArray]];
positionInDwarfArray++;
}
}
[arrayOfPages addObject:page];
}
NSMutableArray *currentPage = [arrayOfPages objectAtIndex:pageNumber];
SKSpriteNode *dwarfJobPermissionBoxBackground = [[SKSpriteNode alloc]initWithColor:[SKColor blackColor] size:CGSizeMake(_initialScreenSize.width/1.1, _initialScreenSize.height/2)];
dwarfJobPermissionBoxBackground.position = CGPointMake(_initialScreenSize.width/2, _initialScreenSize.height/2);
[_dwarfJobPermissionBox addChild:dwarfJobPermissionBoxBackground];
for (int i = 0; i < currentPage.count; i++) {
DTDwarf *tempDwarf = [currentPage objectAtIndex:i];
SKLabelNode *dwarfNameLabel = [[SKLabelNode alloc]initWithFontNamed:@"Arial"];
[dwarfJobPermissionBoxBackground addChild:dwarfNameLabel];
dwarfNameLabel.text = tempDwarf.name;
dwarfNameLabel.fontSize = 15;
dwarfNameLabel.position = CGPointMake(-dwarfJobPermissionBoxBackground.size.width/3.5, dwarfJobPermissionBoxBackground.size.height/2 - dwarfJobPermissionBoxBackground.size.height/7 - (i * (dwarfJobPermissionBoxBackground.size.height/numDwarvesPerPage)));
SKLabelNode *dwarfJobLabel = [[SKLabelNode alloc]initWithFontNamed:@"Arial"];
[dwarfJobPermissionBoxBackground addChild:dwarfJobLabel];
dwarfJobLabel.text = [self getStatusName:tempDwarf];
dwarfJobLabel.fontSize = 15;
dwarfJobLabel.position = CGPointMake(dwarfJobPermissionBoxBackground.size.width/5, dwarfJobPermissionBoxBackground.size.height/2 - dwarfJobPermissionBoxBackground.size.height/7 - (i * (dwarfJobPermissionBoxBackground.size.height/numDwarvesPerPage)));
SKLabelNode *dwarfAgeLabel = [[SKLabelNode alloc]initWithFontNamed:@"Arial"];
[dwarfJobPermissionBoxBackground addChild:dwarfAgeLabel];
dwarfAgeLabel.text = [NSString stringWithFormat:@"%i", tempDwarf.age];
dwarfAgeLabel.fontSize = 15;
dwarfAgeLabel.position = CGPointMake(dwarfJobPermissionBoxBackground.size.width/2.5, dwarfJobPermissionBoxBackground.size.height/2 - dwarfJobPermissionBoxBackground.size.height/7 - (i * (dwarfJobPermissionBoxBackground.size.height/numDwarvesPerPage)));
}
//dont show the page change buttons if at the start or end of the array of pages
if (pageNumber > 0) {
SKSpriteNode *lastPageButton = [[SKSpriteNode alloc]initWithColor:[SKColor blueColor] size:CGSizeMake(dwarfJobPermissionBoxBackground.size.width/5, dwarfJobPermissionBoxBackground.size.height/5)];
[dwarfJobPermissionBoxBackground addChild:lastPageButton];
lastPageButton.position = CGPointMake(-dwarfJobPermissionBoxBackground.size.width/3, -dwarfJobPermissionBoxBackground.size.height/1.5);
lastPageButton.name = @"lastJobPermissionPage";
}
if (pageNumber < arrayOfPages.count - 1) {
SKSpriteNode *nextPageButton = [[SKSpriteNode alloc]initWithColor:[SKColor blueColor] size:CGSizeMake(dwarfJobPermissionBoxBackground.size.width/5, dwarfJobPermissionBoxBackground.size.height/5)];
[dwarfJobPermissionBoxBackground addChild:nextPageButton];
nextPageButton.position = CGPointMake(dwarfJobPermissionBoxBackground.size.width/3, -dwarfJobPermissionBoxBackground.size.height/1.5);
nextPageButton.name = @"nextJobPermissionPage";
}
}
The code works, but certainly there are some problems. All of the code involving drawing boxes and text with SpriteKit is long and potentially confusing. I'm not sure what to do about that. I'm also not sure if the flow of the logic is clear to the reader.
UIKit
views to theSKView
is the wrong way to go about this. The easiest solution is probably to use aUICollectionView
, with each cell in the collection view containing theUILabel
's that you need. Then addSKScene
/SKView
for whatever sprite kit graphics you need--if this is even possible. \$\endgroup\$