I use TortoiseSVN at work as my SVN client on Win7. This has taken some getting used to; at all my previous jobs I used only Perforce. Perforce has influenced me, because I still prefer an app like Versions on OSX to the shell integration of TortoiseSVN. However, it’s here to stay, so I have to make it as efficient as possible.

Customize the Right-Click Context Menu

One peeve I have with TortoiseSVN is the clumsy nested context menu. I hate having to click on the functions in the second menu, like this:

Nested right-click menu

I use some options in the second menu quite often, such as Check for Modifications and Diff. Fortunately, we can customize the menu and take them out of the nested list. First, open the nested TortoiseSVN menu and click on Settings.

Next, click on Context-Menu in the left-hand navigation pane.

Choose your favorite commonly used operations, and click apply.

I personally suggest adding Diff, Check for modifications, and Add. Diff and Add will only appear when they make sense contextually, so they are low-cost and high benefit. Here’s the result:

Use Diff Merge with TortoiseSVN

DiffMerge is a great diff tool, especially because it’s free. It is particularly good for 3-way merging, as compared to the default tools included with TortoiseSVN. You owe it to yourself to at least upgrade to DiffMerge, if not a paid product. In my opinion, Araxis Merge Pro is the best paid tool, but it’s quite expensive. Beyond Compare is very reasonably priced. I use those at work, but at home I make do with DiffMerge, which is still very good. After downloading and installing the software, take note of the install directory. For x64 Win7, diff merge is installed at:

C:\Program Files\SourceGear\Common\DiffMerge\sgdm.exe

To setup DiffMerge with TortoiseSVN, first enter the Settings menu as shown in the first step above.

  1. Navigate to the Diff Viewer under External Programs in the left-hand Navigation pane.
  2. Click the External radio button
  3. Enter the following code into the text pane:
C:\Program Files\SourceGear\Common\DiffMerge\sgdm.exe /t1=Original /t2=Mine %base %mine

Note that you will have to change the path to match the install location, obviously. It should look like this:

Next, do the same for the Merge Tool on the left navigation pane, except use the following code:

C:\Program Files\SourceGear\Common\DiffMerge\sgdm.exe /t1=Theirs /t2=Base /t3=Mine /r=%merged %theirs %base %mine

It should look like this:

Hit Apply, and go ahead and resolve something!

Ahh, much better!

Your Changes Should Appear on the Right

I originally got these steps from Manik Software, which is the first hit I get if I Google “tortoisesvn diffmerge”. Thanks to them, I was able to easily setup DiffMerge for TortoiseSVN. However, their example puts your code on the LEFT, instead of the right, which I think is wrong. Every tool I have used for comparing has always put the base on the left and your changes on your right. If you do it their way, you won’t be able to edit your file while diffing when using DiffMerge, because it disables edits to the left file. It is useful to adhere both to the convention and to be able to edit inside DiffMerge, so I recommend using the steps above.

I wrote this article for my own benefit, so that I wouldn’t forget how to do these things. I hope it’s useful to you. If I find other tricks that I find useful for TortoiseSVN, I will add them to this article in the future. I’m open to suggestions!

Enjoy using TortoiseSVN!


Recently a colleague asked me to help him talk to NAIT students graduating from a game development program. The presentation was on getting hired in the industry, and my artist friend wanted a programmer’s perspective. I came up with some tips, focusing primarily on the interview step, and I thought that it might be useful to others. This article assumes that you already know some basic advice about resumes and interviews. There are lots of sources of information on those topics, and they are not specific to programming, so I will not discuss them here.

Most Important Rule

Relax and have fun

The best advice for interviews is just to relax and feel confident. That’s hard when you’re starting out, but it will get easier. And don’t forget to have fun! The questions can be fun to solve, the people you meet will probably be interesting and you might have travelled to a new place to even go to the interview. Enjoy the experience.

What is the interview trying to achieve?

Interviewers have two main goals. They want to ensure that you are at least minimally competent in your area and willing to learn, so that they can train you to their standards. They also want to determine if you are a good fit for the organization. Don’t forget this! Many exceptionally qualified individuals are rejected due to compatibility issues.

What should your goals be? You’re not trying to find any job, you are trying to find a job where you will be happy. Make sure that you are asking questions about the employer. This will also demonstrate your seriousness and interest. Listen to that little voice in your head. If you have serious doubts about the organization now, it’s not a good idea to join them.

The two parties are also trying to find a mutually satisfactory compensation level.

Compatibility Cautions

Compatibility with the team is one of the most important considerations for hiring. There are several common mistakes that turn off employers.

Know the company

If you can’t be bothered to research the games the company makes, why should they bother to interview you?

Burning bridges

Do NOT badmouth previous projects. Be extremely diplomatic and find positives even when discussing the most horrible experiences of your life. The game industry is extremely inbred and networking focused. Speaking badly about your former coworkers can indicate that you are a poor team player. It also tells the company that you are likely to badmouth them as well if you leave.

Closely related career advice is to be careful when leaving a company. Try to maintain an amicable atmosphere. Participate in exit interviews if they are used. You need references and goodwill to get good jobs in the future, and afterwards, you will feel better about yourself if you behaved honorably.


Arrogance is one of the most destructive traits a programmer can have, regardless of experience. Why? Because in order to learn, you must accept that there are things you don’t know, and you can’t do that unless you are humble.

If you have a lot of arrogance and you are just starting out, it also indicates some stupidity or naivete on your part. Don’t confuse confidence with arrogance. Confidence comes naturally from within; arrogance is usually aggression based.

A common example of a bad idea is telling the studio you are applying to that they are doing everything wrong, and that if they just used design pattern X that you just read from a book, everything would work better for them. Instead, think about why they are not using that technique. Ask them about it! You’ll almost certainly learn something about the techique or the studio or both.

Common Types of Questions

  • Implementation
  • Code comprehension
  • Previous work and background
  • Puzzles
  • Insight questions


Goal: Can you actually program?
Examples: implement a stack; fizz buzz test; parse a string, etc.

Code comprehension

Goals: Can you read other people’s code? (very important for teams)
How good is your grasp of this particular language?
Examples: find some bugs in this code; what does this do?; in what situations would you prefer this data structure over this one?

Previous work and background

Goals: Can you explain technical things quickly and clearly?
Are you passionate and knowledgeable about your work?
Examples: tell us about this project; what technique did you use to get
this effect?; did you encounter this known problem while working with that?


Goals: To try to measure your intelligence.
To see if you can come up with solutions to novel problems under pressure.
Examples: Many examples on the web; Microsoft used to use these heavily

Insight questions

Goals: These have a hidden agenda to learn something about your personality, not to actually see if you can solve the question
Examples: piano tuners, no right answer, seemingly impossible

Insight question examples


How many piano tuners are there in New York?
The point of this question isn’t to have an actual number, it is to see your thought process during the estimation. “Well, maybe 1 person in 100 has a piano, and they get it tuned 3 times a year… etc”

No right answer

If I needed you to solve a Rubik’s cube in the next hour, how would you do it?
You propose a solution, and they give you a new condition that invalidates it. The point of this question isn’t to solve the problem, it’s to see how many different answers you can come up with quickly.
“look up steps on the internet” -> internet is down
“program to solve it” -> no computer
“peel off labels” -> colored plastic instead of labels
“use a screwdriver to reassemble cubes” -> no tools

Seemingly impossible

How could three non-collinear points not lie in the plane that they generate?
Mathematically, the answer is they can’t, this is impossible. But on a computer, this could happen due to floating point precision issues. Here you want to back up and see if there is an out of the box solution.


How would you rate your C++ programming skills from 1 to 10?
C++ is full of dark corners and edge cases. It’s possible you are a true C++ guru, but it’s not very likely unless you have spent a lot of time working on esoterics. This question tries to see if you are overconfident about your skills. When working on games, it’s better to have a good grasp of the parts of C++ that you will actually be using. For areas that involve strange behaviour and language difficulties, it’s usually better to simply avoid them. Remember, your code needs to be readable for the entire team. Therefore, your pure C++
rating will probably be a 7 or an 8, not a 9 or a 10.

General Advice for puzzle/insight questions

Relax, and take your time.

Often the biggest problem is overthinking the question.

Talk though the problem. This is really important, because with most of these questions they want to know how you think, not just get an answer. They might actually be disappointed by an instant answer with no thought, because it might just indicate that you’ve heard that one before, and they still haven’t learned anything about you.

Don’t be afraid to ask questions about the problem to clarify it, or if you are stuck. If a problem seems really hard, or doesn’t make sense, step back from solving it and ask yourself why they might want to ask that question. Basically, do a little check for a trick question.

Don’t worry if you can’t answer all the questions, especially if you had a partial solution or if the question sparked a good discussion.

As for “real” technical questions, it’s difficult to offer specific advice for all companies, as the questions will vary a lot. Here are some possibilities:

  • pointers, pointer arithmetic, post-increment tricks
  • string manipulation, often with pointers, as above
  • find errors in code, some common examples:
    • uninitialized data
    • return arguments not set
    • problems with complex logic (infinite loops, continues or breaks, etc)
    • lack of const correctness
    • exception unsafe
  • vectors
    • dot product
    • cross product
    • intuitive understanding of these graphically
    • How can you easily compute the volume of a parallelepiped?
    • be prepared to apply them to a practical coding question
  • matrices
    • transforms: scale, translate, rotate
    • affine inverses
    • linear algebra
    • again, intuitive understanding of their applications
  • quaternions
    • why do they matter?
    • What is gimbal lock?
    • common use cases
  • inheritance, multiple inheritance
    • what can go wrong?
    • can virtual calls be expensive and why?
    • Good companies will want you to explain why these methods often SUCK.
  • data-oriented design
    • importance of knowing your data
    • designing for common case instead of exceptional case
    • homogeneity via sorting or preparing your data
    • avoidance of virtual functions
    • SOA vs. AOS
    • hot and cold data
  • bit-manipulation tricks
  • hardware knowledge
    • How can optimizing something for memory actually make it faster?
    • Know anything about data-oriented design?
    • What’s a LHS? Cache-miss? Branch misprediction?
    • Relative costs of those things?
  • SIMD
    • what exists for your platform
    • swizzle and deswizzle
    • latency vs. throughput, how to maximize SIMD effectiveness?
    • loading/unloading from floats to vectors
  • multithreading
    • concurrency and it’s problems
    • costs of solutions such as mutex locking
  • STL
    • how to use it
    • issues with it
    • performance
    • alterative containers for your platform
  • exceptions
    • are they good or bad? why?
    • What kinds of code errors can happen?

Try not to over-study any one area. This is a very broad and big list. It’s entirely possible many of the questions will not fall into what you study, so worrying about this too much will just stress you out.

However, reviewing all of it a little bit will make you feel more confident.


Remember: Just relax and try to actually have some fun.


Obviously, opinions on interviews are highly subjective and personal. Also, this advice is biased towards the game industry, as that is my interest and the source of my experience

Just a quickie for today.

It’s pretty trivial to write a keyboard handler in AS3. However, I found it more annoying to simply create a nice complete keycode class where I can refer to all the keys by named constants.

There are one or two pages with the info (with some minor errors), but it’s not in a very convenient format. Therefore, I give you the Keys class for your convenience:

public class Keys
static public const BACKSPACE:uint = 8;
static public const TAB:uint = 9;

static public const ENTER:uint = 13;
static public const SHIFT:uint = 16;
static public const CONTROL:uint = 17;
static public const ALT:uint = 18;
static public const PAUSE:uint = 19;
static public const CAPS_LOCK:uint = 20;

static public const ESCAPE:uint = 27;

static public const SPACE:uint = 32;
static public const PAGE_UP:uint = 33;
static public const PAGE_DOWN:uint = 34;
static public const END:uint = 35;
static public const HOME:uint = 36;
static public const LEFT:uint = 37;
static public const UP:uint = 38;
static public const RIGHT:uint = 39;
static public const DOWN:uint = 40;

static public const INSERT:uint = 45;
static public const DELETE:uint = 46;

static public const ZERO:uint = 48;
static public const ONE:uint = 49;
static public const TWO:uint = 50;
static public const THREE:uint = 51;
static public const FOUR:uint = 52;
static public const FIVE:uint = 53;
static public const SIX:uint = 54;
static public const SEVEN:uint = 55;
static public const EIGHT:uint = 56;
static public const NINE:uint = 57;

static public const A:uint = 65;
static public const B:uint = 66;
static public const C:uint = 67;
static public const D:uint = 68;
static public const E:uint = 69;
static public const F:uint = 70;
static public const G:uint = 71;
static public const H:uint = 72;
static public const I:uint = 73;
static public const J:uint = 74;
static public const K:uint = 75;
static public const L:uint = 76;
static public const M:uint = 77;
static public const N:uint = 78;
static public const O:uint = 79;
static public const P:uint = 80;
static public const Q:uint = 81;
static public const R:uint = 82;
static public const S:uint = 83;
static public const T:uint = 84;
static public const U:uint = 85;
static public const V:uint = 86;
static public const W:uint = 87;
static public const X:uint = 88;
static public const Y:uint = 89;
static public const Z:uint = 90;

static public const NUM_0:uint = 96;
static public const NUM_1:uint = 97;
static public const NUM_2:uint = 98;
static public const NUM_3:uint = 99;
static public const NUM_4:uint = 100;
static public const NUM_5:uint = 101;
static public const NUM_6:uint = 102;
static public const NUM_7:uint = 103;
static public const NUM_8:uint = 104;
static public const NUM_9:uint = 105;
static public const NUM_MULTIPLY:uint = 106;
static public const NUM_ADD:uint = 107;

static public const NUM_MINUS:uint = 109;
static public const NUM_PERIOD:uint = 110;
static public const NUM_SLASH:uint = 111;
static public const F1:uint = 112;
static public const F2:uint = 113;
static public const F3:uint = 114;
static public const F4:uint = 115;
static public const F5:uint = 116;
static public const F6:uint = 117;
static public const F7:uint = 118;
static public const F8:uint = 119;
static public const F9:uint = 120;
static public const F10:uint = 121;
static public const F11:uint = 122;
static public const F12:uint = 123;
static public const F13:uint = 124;
static public const F14:uint = 125;
static public const F15:uint = 126;

static public const NUM_LOCK:uint = 144;
static public const SCROLL_LOCK:uint = 145;

static public const SEMICOLON:uint = 186;
static public const PLUS:uint = 187;
static public const COMMA:uint = 188;
static public const MINUS:uint = 189;
static public const PERIOD:uint = 190;
static public const SLASH:uint = 191;
static public const TILDE:uint = 192;

static public const LEFT_BRACKET:uint = 219;
static public const BACKSLASH:uint = 220;
static public const RIGHT_BRACKET:uint = 221;
static public const QUOTE:uint = 222;

// This class should not be instantiated, just use it's static members
public function Keys()
New to Something Interesting Something Cool? See the explanation here.

This thorough summary and analysis of reflection in C++ by Don Williamson impresses me. To avoid fatigue, I suggest waiting to read part 2 until next issue.

I have fallen in love with Exposé and related functionality in Mac OS X. Recently I found the wonderful application Switcher which has many of the same features for Windows. For the most realistic experience possible, I used F3 as a hotkey and I set it up so that a second press of F3 closes Switcher again.

Does this method of development sound familiar?

Laurie Cheers, a solo developer working out of Vancouver, created a fascinating RPG called Wordsmith (requires Unity). I made it this far after 10 minutes or so, can you do better?

Screenshot of Wordsmith gameplay

Laurie also offers up this talk about invention by Bret Victor, including some interesting ideas about user interfaces.

Ariel Gross talks about using E-Prime to communicate. Notice anything about this post? I found it very hard to do, but educational.

Thank you for reading the inaugural issue! Please send in links for next time!

What is Something Interesting Something Cool about?

Inspired by my former Tech Director, Juancho, I will compile a digest of interesting and cool links for programmers. I will post the digest roughly semi-monthly, and then send an email to everyone on the mailing list. Mailing list members can submit new links of articles they have read, and I will include them in future digests.

Members can submit links to articles old or new as long as they feel the article is interesting and relevant to programmers. I intend to have largely technical articles in the digest, but members can submit articles about helpful tools or programs, amusing stories, or jokes as well.

Contact me to add or remove yourself from the mailing list.

tl;dr version:

  1. Install DiffMerge, place it directly into the Applications folder
  2. Install Versions
  3. Set Versions to use DiffMerge for diffs: Versions->Preferences->File Comparison->Select DiffMerge from dropdown
  4. Download CallDiffMerge from this blog, and place it somewhere accessible on your desktop
  5. When you get a conflict in Versions, select the .mine, .rXX and .rYY files, and drag and drop them onto the CallDiffMerge icon.
  6. Profit from faster and easier merging!

Details and explanation:

I recently began contracting after working in AAA games, and all of a sudden I had to use my mac laptop for actual development.  Previously I had only used my laptop for programming small side projects in which I was the only developer. For those purposes, SVN with command-line interface was fine. But just one merge session with SVN’s awful <<<< notation was enough to make me desperately miss Perforce and Araxis Merge.

If you’re a programmer, though, you don’t get to complain. If your tools suck, fix them yourself! Problem solving is what you do, isn’t it?

So let’s get to work. The first step is to find tools that are cheap or free that get us as close as possible to the solution. I had heard about DiffMerge some time ago, so I decided to look it up. Turns out that it’s a pretty damn good program for diff and 3-way merging. It’s not quite as awesome as Araxis, but SourceGear is giving it away for free!

Next, I investigated combining DiffMerge with the CLI for SVN. This post from the Semi-Crazy blog details that approach, and gave me the inspiration for my Versions approach later. However, I still wasn’t happy with the result. It didn’t look particularly fun to use the CLI to trigger DiffMerge.

The next breakthrough was when I heard about Versions from a friend of mine. Versions was just what I wanted in a source control interface. It’s easy to set up (I never referred to any documentation), easy to use, and has a nice GUI interface. It’s not free, but 40 euros doesn’t break the bank either, and there is a 30 day trial.

How to improve the default diff, though? It’s very easy to point Versions at DiffMerge. Simply select Versions->Preferences from the menu, and in the popup that appears, choose DiffMerge from the dropdown box labelled File Comparison. This is how it should look:Versions Preferences Dialog

But diffs aren’t the true test of source control. Merging is the most complicated and error-prone activity. The first time I got a conflict in Versions, I was pretty excited. Versions showed this (which I later learned is actually provided by SVN itself):

That is everything you need to do a 3-way merge. We have the local file with our changes (.mine), the common ancestor file or base file (.rX) and the most recent or head file checked into SVN (.rY). Note that the revision number for the base file is always less than the revision number for the head file (X < Y). Finally, we also know which file we want to save the merge result to, that’s simply the filename without the .mine. We also know from the Semi-Crazy blog link above, that it’s easy to call DiffMerge with those four arguments.

So we’re done, right? Surely Black Pixel, the folks in control of Versions, have made this an easy to configure option, just like the file comparison?

Sadly, no. Even delving into their custom comparison scripts doesn’t help us in this case, as there is no option to include the common ancestor, which we need. Please fix this, Black Pixel, and make the custom app I created superfluous!

We’re so close. Let’s not give up just yet. First I examined the manual approach, which goes like this:

  1. Click DiffMerge to run it
  2. Click 3-pane button
  3. In the dialog that pops up, drag and drop the 3 files we need to do the merge one by one
  4. Be careful to get them into the right order, or you will get garbage
  5. Click the merge button in DiffMerge to trigger the automerge
  6. Manually merge the conflicts
  7. Remember to Save As… and use the correct result filename

Uh, no. Way too much work, and error prone to boot. So I started thinking about having an app where I could just drag and drop the three files, have it run some kind of script to figure out which files were which, and then call DiffMerge using the approach given in the Semi-Crazy blog. I looked into simple Cocoa apps that support droppable windows, but I’ve never made a Cocoa app, so that seemed like quite a detour.

Enter Platypus, by Sveinbjorn Thordarson. Could we get any more lucky? Here’s an app that creates apps for us, and those apps can support droppable input, and can trigger arbitrary scripts. Not only that, but it’s a pleasure to work with. Clearly, Sveinbjorn is a god among men.

5 hours of bashing my head into my keyboard in frustration over Bash scripting, and I produced this handy script:

# A script that submits a SVN merge conflict trio to DiffMerge.

if [ "$#" != "3" ]; then
  echo "Must call function with 3 filenames, local version, head revision, base revision"



for filename in "$@":
  if [ ${filename##*.} = $LOCAL_EXT ]; then
    if [ -z $OLDEST_REV ]; then
    elif [ $revision -lt $OLDEST_REV ]; then
    elif [ $revision -gt $NEWEST_REV ]; then

if [ -z $LOCAL ] ||  [ ! -e $LOCAL ]; then
  echo "Cannot find local file $LOCAL"
elif [ -z $HEAD ] ||  [ ! -e $HEAD ]; then
  echo "Cannot find head file $HEAD"
elif [ -z $BASE ] ||  [ ! -e $BASE ]; then
  echo "Cannot find base file $BASE"
elif [ -z $SAVE ] ||  [ ! -e $SAVE ]; then
  echo "Cannot find save file $SAVE"
elif [ $HEAD = $BASE ]; then
  echo "Cannot distinguish head from base. There should be two files with different revision numbers"

echo "Calling diff merge..."
echo "Local file:"
echo $LOCAL
echo "Head file:"
echo $HEAD
echo "Base file:"
echo $BASE
echo "Save output to:"
echo $SAVE


${DIFFMERGE_EXEC} --nosplash -m -t1="Head"  -t2="Base (merged)" -t3="Local" -r="$SAVE" "$HEAD" "$BASE" "$LOCAL"


The script checks for various errors, determines automatically which input files are which (in case the order changes) and calls DiffMerge. It tells DiffMerge to save to the correct file, and tells DiffMerge to do the initial “easy” merge right away.

Finally, I just wrapped this script into an app, CallDiffMerge, by following the documentation, which was ridiculously easy. I placed the resulting app on my desktop below my Dock, where it’s visible all the time:

And now, in order to do a three-way merge from Versions, I just have these simple steps:

  1. Select the files in Versions and drag and drop onto the icon
  2. manually merge conflicts in DiffMerge
  3. Save and close.

You can download CallDiffMerge and try it yourself. It should work on any Mac OS X 10.4 or later. Note that the script depends on DiffMerge being directly in the Applications folder. It’s also easy to make changes to the script I supplied above and roll your own app using Platypus.

If you like this tool, please donate to Platypus, as it is the real awesome sauce here.

Improvements I’d Like To See:

Even better than dragging and dropping the files would be selecting them and hitting a key combination to trigger CallDiffMerge. That way the app could be hidden, and you would need less mouse manipulation. Any Mac gurus know how I might be able to do that?

I used the error output during script development, but then I changed my Platypus app for release to close immediately on completion. Is there some way of having that both ways? The app should auto-close when there is no errors, but when there is an error, it should stay open with a text window giving us helpful feedback.

Have Versions do this for me! Seriously, Black Pixel, it’s not hard to have this embedded into the Versions app itself. Or have I missed something obvious?

Uncharted 2

November 16, 2010

I finished God of War 3 the other day so I picked up Uncharted 2 to fill the gap. I had heard a lot of good things about Uncharted 2 with respect to story, game-play, and tech. My first session lasted more than an hour and was enough to hook me on the story: a young, edgy Indiana Jones in search of Marco Polo’s lost treasure. The first mission was to break into a museum to find the first clue.

I think there were a few early scenarios that taught me some movement and stealth basics before I was thrust into a large room with 8 guards, some with flashlights. The guards didn’t move much. The ones with flashlights would turn occasionally and casually scan for intruders. Simple, right? Navigate the level, sneak up on each guard in turn, and take him out. Fun too. One needs to analyze the level and synthesize the jumping, climbing, and sneaking skills into it.

Several attempts showed that some routes were viable and some were not. If you get spotted at all, the jig is up and you need to re-start the level. It seemed that guards could see me from a considerable distance if I was in their front 180 degree arc. Stealth kills were not 100% reliable. Occasionally, I’d move just a bit too quickly or get a bit too close before initiating my attack and have to take my opponent out with a loud and messy 3-hit combo. Well, seemed loud as a viewer, but the combo seemed just as stealthy as a sleeper hold with respect to other guards in the area.

Several more attempts. Wow! The button I use to enter cover executes a dramatic dive roll when there’s no cover around to enter. Some geometry is cover and some is not and it’s not clear which is which. Thus I found myself dive-rolling out into the open, right into the center of flashlight beams, as I frantically tried to get into cover and remain undetected.

Sometimes I’m in cover parallel to a guard with a flashlight and he shines his flashlight on my cover to detect me. What? Is my head sticking up or something? Are they using precision ray-casts to detect me while I’m in cover?

More tries. Hm. If I’m in cover, I can sneak right up beside this guy. I’m in cover, right beside him, close enough to tie his shoelaces together, and he can’t see me.

Achievement: Stealth Killer. Achievement: Unarmed Combatant. I finished two achievements figuring out the first real game-play scenario. Um. Hey Naughty Dog, maybe try some focus-testing next time?

I learn the pattern. Three guards left. I sneak up behind one guy on a balcony and successfully initiate the stealth kill. Except the game chooses the 6-second sleeper hold rather than the 1-second blackjack take-out and I get caught again. Awesome. Try again. Turns out you don’t need to sneak up on this one. You can jump up onto the balcony into the light. I’m not even talking ambient light. I’m talking a point source light painting an explicit globe of illumination in the game, right beside the guard. This is where I “hid” to take out this guard. Then my in-game buddy takes out the other two and the level is over.

I’d say I spent 2 hours figuring out this level. I’m a gamer. It took me 2 hours. I earned 2 “achievements”. What’s wrong with this picture? My follow-up post to this will be about game language and how game developers should consider very carefully how they communicate with their players.

Got an opinion on my play session? Played Uncharted or the sequel?