cs193p – Assignment #3 Task #6

Please note, this blog entry is from a previous course. You might want to check out the current one.

Instead of drawing the Set cards in the classic form (we’ll do that next week), we’ll use these three characters ▲ ● ■ and use attributes in NSAttributedString to draw them appropriately (i.e. colors and shading).

We need to adjust the title of the card and its background thus we need to make those methods publicly available to be able to change it in the set-card-game-view-controller subclass. The method to generate the title uses normal strings at the moment, we need to change this to attributed strings:

- (NSAttributedString *)titleForCard:(Card *)card;
- (UIImage *)backgroundImageForCard:(Card *)card;

Adjust the title method to return attributes strings:

- (NSAttributedString *)titleForCard:(Card *)card
{
    NSAttributedString *title = [[NSAttributedString alloc] 
        initWithString:card.chosen ? card.contents : @""];
    return title;
}

… and change interface-update method:

- (void)updateUI
{
    for (UIButton *cardButton in self.cardButtons) {
        ...
        [cardButton setAttributedTitle:[self titleForCard:card]
                              forState:UIControlStateNormal];
        ...
    }
    ...
}

In the set-card-game-view-controller subclass overwrite the method for the background using two new button images:

- (UIImage *)backgroundImageForCard:(Card *)card
{
    return [UIImage imageNamed:card.chosen ? @"setCardSelected" : @"setCard"];
}

Create those images as 40×40 (and 80×80) images to let the user see the difference of a selected and unselected card … and add them to your image assets.

Setting the title is the most “difficult” part of this task. Create a string with a dummy content and an empty dictionary for the string attributes, which at the end are used to create the attributed string. If the card is not a set card, return an attributed string based on those default values.

If the card is actually a set card get the symbol type from the card, set the symbol string and use the symbols the number of times the card indicates.

For the color of the card add an attribute with the appropriate color to the dictionary.

Use the stroke-width attribute for open (5) and solid (-5) symbols … better would be to use constants … for striped symbols lighten the fill color a little bit:

- (NSAttributedString *)titleForCard:(Card *)card
{
    NSString *symbol = @"?";
    NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];    
    if ([card isKindOfClass:[SetCard class]]) {
        SetCard *setCard = (SetCard *)card;        
        if ([setCard.symbol isEqualToString:@"oval"]) symbol = @"●";
        if ([setCard.symbol isEqualToString:@"squiggle"]) symbol = @"▲";
        if ([setCard.symbol isEqualToString:@"diamond"]) symbol = @"■";        
        symbol = [symbol stringByPaddingToLength:setCard.number
                                      withString:symbol
                                 startingAtIndex:0];
        if ([setCard.color isEqualToString:@"red"])
            [attributes setObject:[UIColor redColor]
                           forKey:NSForegroundColorAttributeName];
        if ([setCard.color isEqualToString:@"green"])
            [attributes setObject:[UIColor greenColor]
                           forKey:NSForegroundColorAttributeName];
        if ([setCard.color isEqualToString:@"purple"])
            [attributes setObject:[UIColor purpleColor]
                           forKey:NSForegroundColorAttributeName];        
        if ([setCard.shading isEqualToString:@"solid"])
            [attributes setObject:@-5
                           forKey:NSStrokeWidthAttributeName];
        if ([setCard.shading isEqualToString:@"striped"])
            [attributes addEntriesFromDictionary:@{
                 NSStrokeWidthAttributeName : @-5,
                 NSStrokeColorAttributeName : attributes[NSForegroundColorAttributeName],
             NSForegroundColorAttributeName : [attributes[NSForegroundColorAttributeName] 
                                               colorWithAlphaComponent:0.1]
                                                   }];
        if ([setCard.shading isEqualToString:@"open"])
            [attributes setObject:@5 forKey:NSStrokeWidthAttributeName];    
    }
    return [[NSMutableAttributedString alloc] initWithString:symbol
                                                  attributes:attributes];
}

Another difference to the playing-card game is that, the set cards are shown from the start of the game. Where playing cards are generated the first time a card is clicked, the set cards need to be generated when displayed the first time. Thus we need to run updateUI when the view loads:

- (void)viewDidLoad
{
    [super viewDidLoad];
    [self updateUI];
}

… and because that method is currently private we need to declare it in the public interface of the parent game-view-controller class:

- (void)updateUI;

With the update on viewDidLoad it is not really necessary to adjust storyboard to the new images. But as you might want to adjust the font size any way, you could also change the images:

cs193p – assignment #3 task #6 – new set-card images
cs193p – assignment #3 task #6 – new set-card images

The complete code is available on github.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.