Jaanus

Musings on my life and work.

Far Cry 3: An Excellent Sandbox Shooter. 10/10

I recently finished the single-player campaign of Far Cry 3. According to Steam, it took me 53 hours.

Wait, what?

Yes. 53 hours.

That’s a huge amount of time to spend on a single-player game. Something like 10 hours might be more typical in my experience.

But, FC3 did take 53 hours over many calendar months. I only played a few hours at a time. And to its credit, not a single moment of it felt like wasted time, too repetitive or boring or some such. It really is a great game. I’ve recently reviewed too many “meh” games here, that I would much rather not replay. But FC3 is one that I truly do recommend if you are a fan of open-air sandbox shooters.

Here’s a video to kick it off, that shows you the highlights of the game.

Now, I’ve played the previous version before. Here’s my review of Far Cry 2. The two main gripes that I had with FC2 were that you can never really secure an area of the map, and the long time it takes to travel between regions. In FC3, both of them have been definitively fixed. When you liberate parts of the island, they are liberated for good. And fast-traveling to previous known locations is as simple as opening the map and double-clicking.

Story-wise, there is no connection to the previous parts of the series. Gameplay-wise though, this feels very much like Far Cry 2 with all of its problems fixed.

When you start to play the game, it can seem overwhelming at first. You need to acquire weapons. You need to craft some syringes. There’s so much to do! Should I follow the stories or side quests?

I can only say, relax and enjoy, because that’s what I did to gain my 50+ hours of gameplay. I did do all the side missions and explored the island. I can recommend that you try to max out on your weapons and gear before proceeding with the story quests, because it then becomes more fun and enjoyable.

How to Add a Custom Separator Supplementary View to UICollectionView

I ran into something recently that I thought might be interesting to post, since I did not see a similar example online: adding custom supplementary views to UICollectionView.

I needed to add a separator in a particular spot between the items within one section. Now, you might do this with collection view sections instead of a custom supplementary separator view. But suppose that you don’t want to re-partition your data into sections, and are just getting a flat array from upstream, and just want to work with that one.

So, without further ado, here’s what it looks like. The code is on Github if you just want to grab it. I’ll discuss some implementation details below.

Limitations

This approach has a few limitations.

  • Only one separator is supported at a time. It wouldn’t be hard to add multiple ones, but the math would be a bit more involved, and I don’t want to overcomplicate the example.
  • Only one-column layout is supported. So in a sense, you could do the same with UITableView, except that UITableView does not have such nice concept of custom supplementary views.
  • Only vertical direction is supported. It would be straightforward to make this work with horizontal scrolling as well, just switching some opeations from y/height to x/width, but it’s outside the scope of the example.

The core idea

When I was more junior and didn’t know any better, I would do horrible things when having to do something like this. Perhaps make the separator part of some cell, or, god forbid, have a custom view floating on top of the table or collection, and scroll it when the rest of content gets scrolled.

Now, though, things are different. UICollectionView and its FlowLayout do most of the heavy lifting for us, and have convenient hooks where we can customize the behavior as we want.

So, we’ll let the FlowLayout work as usual, and then, if a separator is present, just shift the items below the separator down, and draw the separator as a custom supplementary view type. FlowLayout knows only about “header” and “footer” supplementary views, but there’s no contract saying that we can’t have additional custom supplementary views in addition to these, so we do exactly that.

So let’s get started and implement this.

Register the custom supplementary view.

We don’t need a subclass or anything (although we could), we just register the ReusableView class, and handle its layout inline in the controller.

1
2
3
4
5
6
7
8
9
10
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.

  // Register the separator class.
  [self.collectionView registerClass:[UICollectionReusableView class]
          forSupplementaryViewOfKind:SeparatorViewKind
                 withReuseIdentifier:@"Separator"];
}

Drawing the custom separator

After everything has been created correctly, the controller eventually gets a call to draw and configure the separator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath
{
  UICollectionReusableView *separator = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:separatorReuseIdentifier forIndexPath:indexPath];

  if ([kind isEqualToString:SeparatorViewKind]) {
      separator.backgroundColor = [UIColor clearColor];

      if (!separator.subviews.count) {

      // … create the subview to represent the line, and set it up
      // if subviews were present, it means this work has already been done

      }
  }

  return separator;
}

The layout object

We’ll need a subclass of FlowLayout that also has some custom delegate methods, since it needs to know about where to draw the separator.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@protocol JKSeparatorLayoutDelegate <NSObject>

/// Index path above which the separator should be shown, or nil if no separator is present.
- (NSIndexPath *)indexPathForSeparator;

/// Check for index path validity, since layout math doesn’t know about the model.
- (BOOL)isValidIndexPathForItem:(NSIndexPath *)indexPath;

@end



@interface JKSeparatorLayout : UICollectionViewFlowLayout

@property (nonatomic, weak) IBOutlet id<JKSeparatorLayoutDelegate> separatorLayoutDelegate;

@end

Content size

We need to return the correct content size. If we don’t do this, everything else will work correctly, but some items will be out of the view and you can’t scroll to them, you just see them when rubberbanding at the end.

1
2
3
4
5
6
7
8
9
- (CGSize)collectionViewContentSize
{
  // Increase the content size by separator height, if one is present
  CGSize s = [super collectionViewContentSize];
  if ([self.separatorLayoutDelegate indexPathForSeparator]) {
      s.height += separatorHeight;
  }
  return s;
}

The element shifting

The real work of the layout happens in the method - (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect. We get a call to it with the rect that is going to screen. We can just shift the elements below the separator down here, and also add layout attributes for the separator itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect
{
  // Grab computed attributes from parent
  NSMutableArray *attributes = [NSMutableArray arrayWithArray:[super layoutAttributesForElementsInRect:rect]];

  // Possible attributes for separator
  UICollectionViewLayoutAttributes *separatorAttributes = nil;

  for (UICollectionViewLayoutAttributes *attr in attributes) {

      // If there should be a separator above this item, then create its layout attributes
      if ([attr.indexPath compare:[self.separatorLayoutDelegate indexPathForSeparator]] == NSOrderedSame) {
          separatorAttributes = [self layoutAttributesForSupplementaryViewOfKind:SeparatorViewKind atIndexPath:attr.indexPath];

            CGRect separatorFrame = attr.frame;
            separatorFrame.size.height = separatorHeight;
            separatorAttributes.frame = separatorFrame;

      }

      attr.frame = [self adjustedFrameForAttributes:attr];

  }

  if (separatorAttributes) {
      [attributes addObject:separatorAttributes];
  }

  return attributes;
}

- (CGRect)adjustedFrameForAttributes:(UICollectionViewLayoutAttributes *)attributes
{
  CGRect f = attributes.frame;
  NSIndexPath *separatorIndexPath = [self.separatorLayoutDelegate indexPathForSeparator];

  // If there is a separator, and this item is below the separator, shift the item down
  if (separatorIndexPath) {
      if ([separatorIndexPath compare:attributes.indexPath] != NSOrderedDescending) {
          f.origin.y += separatorHeight;
      }
  }

  return f;
}

The element shifting, revisited

If you implement the above, and run it, you’ll find that it mostly works, but sometimes there is a gap in the cells.

Uh oh. What gives?

Let’s think about how layoutAttributesForElementsInRect works. It asks for layout attributes of one screenful at a time. (Actually it seems to be two screenfuls on initial run, and one screenful after that, but let’s just think about one screen.) So at first pass, the parent FlowLayout object might give us attributes for items 1-8, next 9-16, then 17-24, and so on.

But: suppose our separator is above item 4 on first screen. So the first screen contains layout for objects 1-3, separator, 4-8. And then, 8 is out of the rect so its attributes are simply discarded. They do not “carry over” to the next screen. Then, at next run, for the next screen, the parent returns attributes for 9-16, but in our case, we might want 8-15. Since 8 is not included, we’ll see a gap in its place.

To compensate for that, there’s some extra math that I’m not pasting here but that you can see in the Github project, that figures out which extra cells to add to the rect, in addition to the ones returned by parent FlowLayout.

Conclusion

UICollectionView is a fairly involved class, but has a lot of flexibility. We can let the parent classes do most of the work, and slightly customize the results from them, instead of having to do a lot of work ourselves. You’ll see that my example project implementing the above solution doesn’t actually have all that much code.

Crysis 3

I finished Crysis 3 the other night. I’ve written about the first and second game in the trilogy before, so let’s wrap this one up.

Here’s a trailer that fairly accurately captures the feel of the third part.

Whereas Crysis and Crysis 2 were very different, Crysis 3 feels much more like a logical continuation of the second part, almost like a Crysis 2.5 rather than a completely new episode. There are some new gameplay elements, like the bow and alien weapons, and nanosuit customization, but overall, it is the same.

It is technically very well executed, a visually gorgeous game with epic landscapes and effects. Some critics say, though, that it is much too dark through a lot of the game. I also don’t like too dark ambiences, and there were a lot of those, though it kept alternating with brighter environments and I wouldn’t say it was too dark.

Still, if I were to have my preference in the series, it would be: Crysis 2, Crysis, Crysis 3. Somehow the third part felt the least fulfilling. Maybe I had outgrown the series or took too long to play the third part (took me about three months of playing every now and then). Hans Zimmer’s intro song was also more captivating in 2.

I like that the third part really does wrap up the trilogy in a meaningful way, and the trilogy overall is definitely one of the most solid instalments of modern FPS gaming.

Chaining Execution

Brent Simmons has a post about his quest to find a solution for blocking on object init while maintaining a synchronous API, and another one about how for most cross-object execution, it makes sense to stay on the main thread and only put background work on the background queue.

I haven’t had to solve the particular problem from his first post, but in a project that I’m working on, I deal with a significant amount of asynchronous execution. It mostly comes from two sources.

First, data. It comes from network, and thus it may or may not be there. Or, it may be there, but not cached/preprocessed in a correct way. So, if someObject deals with the above kind of data, and you have a call like…

1
2
[someObject prepareSomeData];
[self otherCodeToRunAfterPreparingData];

… there really are two paths here. If the data is there, doSomething may return immediately in the same runloop, and execution continues without a hitch. On the other hand, if the data is not there, execution may block for an indeterminate amount of time.

The other case is chaining animations. For a professional UI, it is not uncommon for multiple things to happen after some user input. For example, if you tap a button, it might trigger the following sequence of events:

  • One-shot button animation as feedback to user
  • Objects moving around in the UI (added, removed, shifted around)
  • Each of the added objects animating themselves
  • The object signaling some other object to dismiss a modal view that it was presented in

Running them all at the same time looks like a visual explosion and it is hard for the user to follow what’s happening. Correctly orchestrating such things is a strong sign of good UI polish.

Sometimes I’ve seen these animations chained by timing: the engineer calculates how long each animation takes, and delays the next one by that amount. Not only is this brittle and looks ugly in code, but it may introduce crash bugs, as the context may change during execution: the objects may go away without knowing it themselves, and happily try to run animation when it’s no longer valid to do so.

The solution to both of these things is to use block-based APIs. A strong indication to me that this is the right thing to do is that completion blocks keep popping up left and right in all of Apple’s new APIs. Some of the key ones like presentViewController:animated:completion: have been around for a while, but the trend continues with, say, NSURLSession that has completion handlers as blocks, unlike NSURLConnection that’s based on callbacks (and was, of course, designed long before blocks were a language feature to begin with).

Coming back to the above example, my code has API’s like this all over the place:

1
2
[someObject methodWithCompletionBlock:^{  code  }];
[someObject doSomething:parameter withWidget:widget completionBlock:^{  code  }];

The example from above would thus work better like this:

1
2
3
4
5
6
[self showProgressIndicator]; // maybe put up a spinner to show the user loading progress if it happens to take long
__weak TypeOfSelf *weakSelf = self;
[someObject prepareSomeDataWithCompletionBlock:^{
  [weakSelf hideProgressIndicator];
  weakSelf.something = somethingElse;
}];

A few things to note here.

First, note how we put up a progress indicator, and hide it in the completion block. In the “data available immediately” case, it’s shown and hidden in the same runloop, so it’s like it never happened in the UI. For “data available later” case, it’s immediately shown, and then hidden when appropriate.

Second, the weak self reference. It is absolutely essential to understand the strong and weak business when working with ARC, with code like this that you request to be executed, but have no control over its final scheduling or any idea when it actually gets run. Nor should you care, and if you set up the weak references correctly, you don’t. The block in this example may get run immediately. It may get run as part of a completion block of an animation or download. The target object may strongly retain it and run it after a hardcoded timer. It doesn’t matter. What matters is that your object may go away before the block gets run. When the block contains strong references to the object, it interferes with the normal expected execution flow and the object is held on to longer than you think, unless this really is the desired behavior (but most of the time with API-s like this, it isn’t). Strong references here may result in unexplained behavior, crashes, leaks, and who knows what else. If, on the other hand, you have a weak reference here, and your object happens to be released, then by the time execution gets to the block, weakSelf is treated as nil, and calling methods on nil is harmless. Note that you didn’t have to tear down the block or do anything special with it when your object is released.

Third, note the property usage. This didn’t just randomly appear in the example. If you were to manipulate any of the object’s data like variables in a block like this, the most straightforward thing to do is to make them properties. Were you to use an ivar directly in the block, it would create an implicit strong reference to self, and your memory management is again screwed. Accessing weakSelf properties, on the other hand, is fine.

An often-critiqued similar API is NSNotificationCenter addObserverForName:object:queue:usingBlock:. I think it’s a great API for running simple code triggered by notifications, and I have never myself had a single memory management problem with it, when I’ve stuck to the weak reference rules. It sounds an awful lot like people are blaming the tools for not being able to implement things correctly themselves. Sure, tools could be better to warn us about implicit strong references. Clang sometimes does this with warnings, and sometimes as static analyzer result. But all the tools are there today to do this correctly.

On the callee/target side, one thing to note is that the block may be nil, and if you then try to call it, it crashes. Just check for its validity. Other than that, nothing special, so this kind of nesting is pretty common for me these days:

1
2
3
4
5
6
7
8
9
10
- (void)someMethodThatTakesBlock:(void (^)(void))blockName {
  [self presentViewController:someVc animated:YES completionBlock:^{
      [UIView animateWithDuration:something animations:^{
           something
      } completion:^(BOOL finished) {
           wrap up the animation
          if (blockName) { blockName(); }
      }]   
  }];
}

(And yes. I did have to go to fuckingblocksyntax.com to see how to correctly write the method parameter.)

The moral in the end? It’s great to be working on iOS and Mac these days if you don’t have to go back in history and can use modern block-based APIs. Blocks and ARC together make it powerful, fun, and safe to deeply nest and chain execution while maintaining clean separation and tight API-s between objects.

Call of Duty: Black Ops

Finished the single player campaign a while ago. According to Steam, took me 8 hours. So it’s on the short side of shooter campains. Didn’t feel too short, though; just about the right length for this kind of game.

The trailer is, of course, impressive. But before I talk about the game itself, let’s talk about (not) getting it to work on Mac. (tl;dr: didn’t work for me.)

Technical problems on the Mac

I could not get it to work correctly. I first bought it from Mac App Store. It installed and ran fine, but at some point in the game, when you got killed, the game just froze with a black screen. (It is supposed to continue from the previous checkpoint in this case.) It kept doing that, so I thought, maybe something is wrong with the MAS version, and I try the Steam version. I asked MAS for a refund, which I got.

One thing about Apple’s customer service which I don’t think is acknowledged enough, is that they have a generous refund policy that doesn’t treat all customers as potential fraudsters. If you ask nicely for a refund and explain it well enough, you just get it, no questions asked. Compare this to Steam’s policy of “no refunds whatsoever under any circumstances.”

Anyway. Many games on Steam are such that you buy it and can install on both Mac and Windows. Not so with Black Ops, which has a separate Mac and Windows version. I bought the Mac one, and sure enough, it misbehaved the same way as the faulty MAS version. Aspyr tech support asked me to try a few things, none of which helped, so I just gave up.

So, I just bought the Windows version, which did not have any technical problems. So unfortunately, Mac still is not up to par for AAA gaming, and performance may vary considerably across titles. (Max Payne 3 had many technical problems. On the other hand, Half-Life and Portal series worked flawlessly for me.)

The game itself

The most important fact about the game is that the single player version was not memorable to me in any way at all. I like to play FPS/adventure games that innovate or contribute something. CoD has by now turned into a mindless franchise that just pumps out a new version every year like clockwork, but they’re shallow and don’t contribute anything to the genre.

It’s not a bad game. It’s well produced. Pieces of it are interesting. Like the whole premise of black ops with different episodes was something new, and the sequence where you switch between guiding special ops team from a SR71 Blackbird, and being said team yourself, was something new. But overall, meh. I’m not sure who their audience is, but I’m not that. And multiplayer is probably very good for people who play it, but I don’t.

What’s my benchmark? I’m now playing Far Cry 3 and Crysis 3. Both of them are way more interesting, especially FC3.

Max Payne 3 and Tropa De Elite

I recently finished Max Payne 3. (According to Steam, it took 17 hours.)

I really liked the first two games in the series, but knew that third one would be a major departure. It’s built by a different team and happens in a different place, years after the events of the first series.

Yet, when I now look back, I feel that it was more of a continuation of the series than I was expecting. Payne voice acting is by the same guy, the bad humor and painkillers are still there, a lot of the mechanics (bullet time) is true to the series’ legacy. Could have been much worse.

Game play wise, this is one of the most tactical shooters I’ve played recently. You really need to use the environment, cover and bullet time to your advantage. If you just run into a situation openly, you’ll get killed in no time, as you can only take a few hits. However, “last stand” is a cool mechanic to recover from this situation: when you get killed but still have painkillers left, you have an opportunity to kill the guy who almost-killed you, and then live on.

Here are some videos about the visuals and game mechanics.

Crossplatform dind’t work for me

One of the supposedly cool things was that the game eventually got released on both Windows and Mac on Steam. (Initially it was Windows-only.) You could play on any platform and share the savegames.

Well, for whatever reason, it just didn’t work. The Windows version (in Windows 7 with Bootcamp on Retina Macbook Pro) ran flawlessly. The Mac version had crappy frame rates, no matter how I tweaked it, and didn’t pick up the save games. I saw some patches published later for it, but it was too late for me then. Maybe it got fixed. But crossplatform gameplay on Steam seems to still be tricky.

Tropa de Elite

On the game’s Wikipedia page, the developers recommend Tropa de Elite, a famous recent Brazilian action movie, that depicts how the special police forces cleans up the favelas in big cities.

I was intrigued, as a lot of Max Payne 3’s action takes place in this exact environment, and the producers had cited this movie as a big inspiration. I wanted to see how close these things really are.

Well, they’re close and I think the producers did a great job. The ambience in the game is very similar to what you see in the movie, with all the Portuguese shouting, tight spaces, destructible environment, lighting, and other aspects. It really does feel like you’re right in that movie when you play. Only, unlike the movie, the game is much more ambiguous about who are the good or bad guys.

Recommendation

I do recommend you play the game if you were a fan of the first two games. It does take and expand the series in a new direction, but it’s a direction that I feel does justice to the legacy of the first two.

The Broken Hand: The Aftermath

Part of The Broken Hand series

The Aftermath

I will probably never gain back the full range of motion for my right arm, but it doesn’t matter. The arm is fully usable in daily life and doesn’t prevent me from sports or anything else. I even got to snowboard two times in this past season. The limited motion only shows when I twist it in strange particular ways, and perhaps, will gradually improve still as I keep doing my exercises.

The accident reminded me that I have a lot to be thankful for. Even when sitting there with my arm stuck in an immobilizer, I realized that I am super lucky to have great support at home, and enough savings and flexible work situation that I wouldn’t have to constantly worry about how to manage and go through this. All it took was my own persistence and sticking to the prescribed routine.

For some time, I could see the world through the eyes of someone who’s not fortunate enough to have a body with two functioning arms. Luckily for me, it was only a temporary situation, but it reminded me that there are many of us out there for whom this will be a reality forever. Really, if you got two working arms and legs, full vision and hearing, you already have a lot to be thankful for.

A Gotcha About Objective-C Categories in the Same File as the Main Implementation

I ran into some weird errors today that made me scratch my head for half an hour until I reasoned through it with my colleagues.

Suppose you have the following implementation file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@implementation SomeClass

- (void)someMethod
{
  [self someCategoryMethod];
}

@end

@implementation SomeClass (SomeCategory)

- (void)someCategoryMethod
{
  [self doSomething];
}

@end

If you built the above, you’d get an error:

No visible @interface for 'SomeClass' declares the selector 'someCategoryMethod'

What gives? I am not a compiler expert and cannot explain it in 100% correct technical terms, but turns out that in this case, top-to-bottom parsing rules apply. The source file is parsed and compiled top-to-bottom. By the time you are trying to call the method, the compiler has not yet seen the method declaration, so it complains.

The fix, thus, is to put the interface ahead of the method call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@interface SomeClass (SomeCategory)

- (void)someCategoryMethod;

@end

@implementation SomeClass

- (void)someMethod
{
  [self someCategoryMethod];
}

@end

@implementation SomeClass (SomeCategory)

- (void)someCategoryMethod
{
  [self doSomething];
}

@end

This works fine. Alternatively, you can just put the category implementation ahead of the main implementation, and that works as well.

Why do I feel it’s worth pointing out? Because it was counter-intuitive to me. The implementation that started this post did not compile, but felt perfectly intuitive for me. It felt intuitive because with recent Objective-C language advances, Apple has trained us that it is not necessary to declare methods within the same implementation file. So, this file would compile perfectly well:

1
2
3
4
5
6
7
8
9
10
11
12
@implementation SomeClass

- (void)someMethod
{
  [self someOtherMethod];
}

- (void)someOtherMethod
{
  [self doSomething];
}
@end

There is no need to declare someOtherMethod ahead of the first time that it is called. I was expecting the same paradigm to extend to category implementations within the same file, but apparently, that is not the case. In case of categories, you need to have the interface/declaration appear before you call it.

The Broken Hand: The Physical Therapy

Part of The Broken Hand series

The Physical Therapy

After such injuries, it is imperative to have therapy. Your arm may be somewhat mobile, but from the weeks of sitting still, there’s no strength left in the muscles. You literally can’t lift it up, and it’s very scary at first. Will I always be like that?

Physical therapy brings on visible progress, and it’s encouraging. I went every few weeks to look at my current state and got a new set of exercises to do several times a day—first with a small ball, then with rubber bands, broomsticks and other household tools. Progress was visible, and I was on my way back to a healthy, regular life.

The Broken Hand: The Follow-up Doctor’s Visits

Part of The Broken Hand series

The Follow-up Doctor’s Visits

I was fortunate to have support at home, so I wouldn’t have to leave to get my food or such. It was all taken care of. But you can’t stay like this forever.

Ten days after my accident, it was time to leave the home for a follow-up doctor’s visit that involved an X-ray and consult. It was a humbling experience. When I was leaving the bus, I got stuck between the automatically-closing doors. It hurt somewhat, but the scare was worse than the pain.

The visit itself was, fortunately, uneventful. The doctor examined my fresh x-rays, did an ultrasound, and told me the good and bad news. The good news was that there were no anomalies or complications, that I had done great by holding my hand still in the sling, and the recovery proceeded as planned. The bad news was that the “as planned” part would take four to six weeks.

Sitting still for weeks sounds difficult, but I kept myself busy with reading and other activities. Besides watching a bunch of movies, including the long-planned “Minority Report” that I still hadn’t found time for previously, I had the above-mentioned professional videos and books.

I was also anxious to get back to work, but it’s complicated when you can’t hold your hands on the keyboard on your desk. I found that a Bluetooth keyboard held in my lap helped a lot.

Initial recovery did indeed take four to six weeks as advertised, and a few more follow-up visits. The immobilizer finally came off right around Christmas time.