Monday, November 15, 2010

What Internet Explorer 9 needs in order to make me switch from Chrome

As I regularly switch between IE8 and Chrome, I’m constantly reminded of the features which IE9 will need in order to make me switch.  I know the particular needs are different for different people, but here are mine:

1. Spell-check

I’m a good speller.  But I still make typos, and there’s still the occasional word that I’m unsure of.  Having to look up unknown words in an online dictionary is an annoyance I shouldn’t have to deal with in 2010.

2. Tab-dragging/removal/insertion

Now that I’ve been spoiled with Chrome’s ability to drag tabs in and out of browser windows into new instances, I’m annoyed when I don’t have this.  I am an unapologetic “tab whore”, and organizing them is important.

3. The ability to switch to another tab while the previous tab is loading/rendering content

Microsoft likes to defend IE’s speed versus Chrome, conveniently measuring only those situations which favor such comparisons.  But here’s a common situation you’ll never see quantified:

I load a page in a tab (either by clicking a link or typing a URL manually).  The page is taking forever to load, so I click to open a new tab (or switch to a currently open tab).  In Chrome, this happens effortlessly.  In IE, however, I’m blocked until the page loads completely.  This is gets old very quickly, and every time it happens, it serves as a reminder for why I prefer Chrome.

4. More efficient URL auto-completion

In Chrome, if I want to visit Facebook, I commonly follow these steps:

1. Click in the address bar.

2. Type the letter ‘f’.

3. Press [Enter].

In IE, it’s these:

1. Click in the address bar.

2. Type the letter ‘f’.  See that the History list has brought up a bogusly-entered URL “http://fa/” from a prior failed attempt to visit Facebook.com.

3. Type the letter ‘a’.  “Facebook” now appears in the History list, underneath “http://fa/”.

4.  Press the down-arrow key twice to select the History entry for Facebook.

5. Press [Enter].

Now, if I know you as well as I think I do, you’re going to launch all sorts of counter-arguments:

You:

“It’s your fault you typed ‘http://fa’ and expected it to work, causing the invalid History entry.”

Me:

One, this would have worked in Chrome, so it just illustrates that Chrome is simpler; and two, Chrome is smart enough not to save bogus URLs in its history, so even if I manually typed http://fa/ in Chrome, it won’t create a History entry for it.  Another strike against IE.

You:

“You can just hit Shift+Enter to load the top URL in your History.”

Me:

So in other words, it’s more complex than Chrome.  Thank you for proving my point.  And I still have to type more characters to eliminate http://fa/ as a history option.

Friday, November 5, 2010

I’ve found that one of the best ways to find a solution to a technical problem at work is to write a lengthy, passive-aggressive email to your coworkers, explaining in detail what you’re trying to do and what’s going wrong.  9 times out of 10, you’ll figure out what’s wrong before you embarrass yourself by hitting the Send button.

Thursday, July 15, 2010

Objective-C MIN and MAX #define wonkiness

Here’s a little odd thing I discovered when trying to use the MIN and MAX macros defined in NSObjCRuntime.h.  I had the following code (simplified):

const int MAX_OBJECTS = 10;
int numObjectsToRemove = MAX(0, myObjectArray.count - MAX_OBJECTS);


Let’s say myObjectArray.count is 1.  What would you expect numObjectsToRemove to become?

0, right?  Because (myObjectArray.count – MAX_OBJECTS) == (1 – 10) == –9, and 0 is clearly greater than –9.  But you’d be wrong.  And so was I.

You see, apparently, since the count member of NSArray is an unsigned int, the entire expression gets treated like an unsigned int.  So, since –9 in unsigned form is actually a very large number, it’s considered greater when compared to 0.  But as if that wasn’t bad enough, when it gets assigned to numObjectsToRemove, it gets treated like a normal signed int again, so its value becomes –9 again.  And you’re left wondering why –9 is considered greater than 0.

The simple fix is to force the macro to treat the whole expression like an int with a simple cast:

int numObjectsToRemove = MAX(0, (int)myObjectArray.count - MAX_OBJECTS);

Tuesday, July 13, 2010

Permission confusion in MS SQL Server 2008

I’m singling out MS SQL Server 2008 though I’m sure this appears in previous versions as well.

Have you ever run into a situation in which, for some reason, you just couldn’t grant someone certain permissions in SQL Server?  If you’re irresponsible like me, you’ll generally just try to give them as much access as possible to make the problem go away sooner.

But there are an insane number of ways you have available to you to change permissions.  Do they all do the same thing?  Are they different windows into the same data, or do they affect different permissions?  Who the heck knows, except the SQL Gods.  Here’s an example of the overwhelming number of ways to assign permissions:

1. Select the Security->Users folder under your database item, and add/modify the property of users from there:

sqlhell_step01

2. Select the Security->Roles folder under your database item, right-click and select Properties on a database role and assign a user to that role.  Bewilderingly, this doesn’t appear to correspond to method #1!  In other words, if I assign a user to the dbowner role using method #1, they won’t be listed in the role membership listing of method #2!

sqlhell_step02

3. Right-click the database object itself, click Properties, then select the Permissions page.  OMG, now there’s a completely separate list of users and very fine-grained permissions which you can “Grant”, “With Grant” (whatever on Earth that means), or “Deny”.  Huh?  Why is there a completely different set of permissions?  Do these override the role memberships?

sqlhell_step03

4. Select a user from Security->Logins of the database server item, edit their User Mapping properties to assign them to a particular database, and from there modify their "Database role membership”.  This seems to correspond to the values in step 1 or 2.

sqlhell_step04

5. RIght-click the database server item and choose Properties, then click the Permissions page.  This allows you to select logins or roles and explicitly assign permissions similar to Step 3.  But you’re assigning these to Logins instead of Users?  Wha?  Does that override the User permission, or does the User value override the Login permission?

sqlhell_step05

 

I’m sure there are many more ways to modify permissions but I’d just be belaboring the point.  I have nothing against having multiple places from which to modify user permissions, but I’d like if there was some semblance of correlation to one another.  As it stands, when I assign someone permissions, I’m mostly just guessing.  I realize that this is a tool for hardcore administrators, but in reality it’s used by a lot of everyday programmer-users like myself.  We aren’t administrators nor do we want to be; we just need to do what we need to do to get our job done.

I have something I want to do and a cryptic way to accomplish this through the administration tool.  What I want is an easier way to specify what I want, and have the system be smart enough to guide me through (possibly multiple) options for making this happen.

Wednesday, June 9, 2010

2D Line segment intersection detection in C#

For a previous game project, I needed a nice line segment intersection detection algorithm.  It was surprisingly difficult to find a good one in C#, but I found one in C++ that I converted. 

As it turns out, my upcoming game makes heavy use of this algorithm as well.  So here it is in case anyone else needs it.  This version is a little sloppy in that it uses 3D constructs despite checking 2D intersections, but it would be simple to convert this to its 2D counterpart.

Line segment intersection C#
  1. // Returns true if the lines intersect, otherwise false. If the lines
  2.         // intersect, intersectionPoint holds the intersection point.
  3.         public bool Intersects2D(LineSegment3 otherLineSegment, out Vector3 intersectionPoint)
  4.         {
  5.             float firstLineSlopeX, firstLineSlopeY, secondLineSlopeX, secondLineSlopeY;
  6.  
  7.             firstLineSlopeX = this.Point2.X - this.Point1.X;
  8.             firstLineSlopeY = this.Point2.Y - this.Point1.Y;
  9.  
  10.             secondLineSlopeX = otherLineSegment.Point2.X - otherLineSegment.Point1.X;
  11.             secondLineSlopeY = otherLineSegment.Point2.Y - otherLineSegment.Point1.Y;
  12.  
  13.             float s, t;
  14.             s = (-firstLineSlopeY * (this.Point1.X - otherLineSegment.Point1.X) + firstLineSlopeX * (this.Point1.Y - otherLineSegment.Point1.Y)) / (-secondLineSlopeX * firstLineSlopeY + firstLineSlopeX * secondLineSlopeY);
  15.             t = (secondLineSlopeX * (this.Point1.Y - otherLineSegment.Point1.Y) - secondLineSlopeY * (this.Point1.X - otherLineSegment.Point1.X)) / (-secondLineSlopeX * firstLineSlopeY + firstLineSlopeX * secondLineSlopeY);
  16.  
  17.             if (s >= 0 && s <= 1 && t >= 0 && t <= 1)
  18.             {
  19.                 float intersectionPointX = this.Point1.X + (t * firstLineSlopeX);
  20.                 float intersectionPointY = this.Point1.Y + (t * firstLineSlopeY);
  21.  
  22.                 // Collision detected
  23.                 intersectionPoint = new Vector3(intersectionPointX, intersectionPointY, 0);
  24.  
  25.                 return true;
  26.             }
  27.  
  28.             intersectionPoint = Vector3.Zero;
  29.             return false; // No collision
  30.         }

Friday, March 19, 2010

Improving music performance in the iPhone SDK

For people who like to copy and paste other people’s solutions without researching the problem in depth, this entry is for you (since I don’t go into depth).

I was noticing my iPhone game framerate being really jerky when playing music that I encoded using IMA4 format, so I changed it to LEI8.  The file format is somewhat big, being lossless, but the tradeoff is that I hardly notice any jerkiness now.

In short, I was previously running this to convert my files before:

/usr/bin/afconvert -f caff -d ima4 Source.mp3 Target.caf

and now I’m doing this

/usr/bin/afconvert -f caff -d LEI8 Source.mp3 Target.caf

I don’t notice any sound quality degradation either.  I also tried LEI16 but it wasn’t worth the doubled size for no noticeable quality gain (Your Mileage May Vary).

Sunday, January 31, 2010

Reflections from Global Game Jam 2010

I posted a characteristically long blog entry via my account at globalgamejam.org, which I will repost here:


I've survived the Global Game Jam, and my team created something resembling a game. To say that I'm happy with it or proud of it would be untrue, unfortunately. It's hard not to look back at all the things that could have been but weren't, or imagine what could have been added if only we had slightly more time.

In the end, we created an espresso stand themed mini-game, essentially. Was it innovative? Not really. Was it fun? Not in its 48-hour state, but there was potential at least. Was it the game I dreamed of making during the months preceding the Jam? No. Why? What went wrong? I will try to address these questions in a way that won't spiral into hopeless negativity.

My first blog entry listed the lessons I learned from my last Game Jam. I want to revisit them to see how well I did, and then see what new lessons I learned from this one:

* Find a team you mesh well with.

My teammates were cool people, but it was clear that we had very different goals and very different sets of experience. Dwelling on this will only sound like blaming, but suffice it to say I didn't do a good job here.

* Use source control.

We had an SVN server up and running pretty quickly, and this saved us. I don't even want to think about the challenges we would have faced otherwise.

* Scale scale scale

Our overall game idea was indeed very straightforward, but we aimed for far too many embellishments than we should have for a 48-hour game. Probably half of the time was spent creating/working with content in some form, rather than coding actual essential gameplay logic. Because of this, we ultimately had to cut key features of the game.

* Throw solid coding practices to the wayside

I feel we reached a really good balance here. Our code was structured in a fairly logical way but with some corners cut for the sake of time (for example, avoiding unnecessary future-proofness by hardcoding logic which assumes two players).

The lessons I learned from this Jam were mostly rehashes/reinforcements of the previous lessons:

* Find a team that you mesh well with, part 2: I had been excitedly anticipating this event for months in advance, and all my friends knew because I talked about it constantly. Naturally I arrived early, brought tons of supplies/food/drinks with me, set up my laptop with source control, etc. ahead of time. I should have immediately seeked out other developers who shared the same passion. And remember, you are inevitably going to have to compromise on a design idea. So find people who have design goals as close as possible to yours (e.g. don't group with someone who is passionate about Myth-esque puzzle games if you really want to make a retro shooter)

Speaking of design, I might get flak for saying this, but for a 48-hour game, a designer with little or no programming experience is dead space unless they're also an artist. Everyone is a designer. Everyone has ideas. Yes, there are good designers and there are horrible designers. But even a great designer who does nothing but design is not worth it on a 48-hour game. More likely than not, a dedicated designer will only increase the scope of the game by dreaming up infeasible features, causing friction with the developers who actually have to [dare I say] do the work.

If you're lucky, you'll find a programmer who is already good-enough at art. The artistic bar is not exactly high for a 48 hour game, so "good-enough" is all you need. A dedicated, exceptional artist is a great asset as well though, because it's often the aesthetics that really boost the appeal of games of this scope.

I didn't mention sound designers, because again, the scope of the game is so small that sound is often an afterthought, but they can be a great addition if you can afford the opportunity cost.

* Scale scale scale, part 2: Your design should be iterative even for a 48 hour game, but a crucial point is that this design should start extremely simple. Find a core mechanic, keep the mechanic DEAD SIMPLE, and if you have time, iterate on it. Here's a counter-example of what I mean:

For our espresso game, "Cheap Shots", the original plan was to have players create different drinks by pressing buttons in a particular sequence on an Xbox controller. So, one drink might be A, B, B, X and another might be X, Y, A, B (the buttons were supposedly associated with different ingredients). Before we had even completed implementing this basic mechanic, we began dreaming up new ways to add ingredients; for example, holding the trigger and releasing it at a particular time might be associated with steaming milk, or turning the thumbstick on the controller might be associated with stirring the drink. This was a mistake from the start. I ended up spending precious amounts of coding time trying to implement these special case scenarios (keep in mind they all required additional UI assets as well), while core gameplay mechanics were being neglected (score board, game timer, essential UI elements, etc.)

Further, we spent what felt like half of our time dealing with mountains of sound assets that were completely non-essential to the gameplay. These were the types of niceties that could be added after the fact, when the core gameplay was done.

So, in short, it's not just the game that needs to be simple; the core mechanic needs to start dead-simple and optionally build from there after you have a complete gameplay experience.

Here are some additional lessons I learned, though some are minor:

* Make sure that your working environment is comfortable.

DigiPen was great. There was an active work environment with plenty of space. But when you're working for 48 hours almost nonstop, even the minor things can become major annoyances. I was foolish enough to position myself in the middle of a long table, separated enough from my team that any time they called me over, I needed to practically climb over my table or else squeeze by several people to get to them. After the 25th time having to do this, I was ready to relocate.

Also, make sure you have the best setup you can get; a large monitor, comfortable mouse, etc.

As soon as you sense an annoyance, fix it, or it'll be a thorn in your side for the next 48 hours.

* Time is precious; don't waste it.

Yes, I know, this is obvious. My point isn't about goofing off excessively or being lazy. If you're inclined to do that at a game jam, you're probably not passionate enough for it to begin with. I'm talking about other time wasters. For example, you don't need to notify your team about every single change that doesn't affect them, show them every cool thing you added, or ask them questions that you can easily find the answer to yourself (i.e. "Where is X defined in the code?"; there's a search function for that). Remember, assuming you picked a good team, their time is every bit as valuable as yours. Every time you interrupt them in the middle of coding, you break their concentration. You force a "context switch", and it takes them time to regain their focus. Don't have needless conversations in which you explain at length how you intend to implement something; just do it. And similarly, don't explain at length how someone elsemight possibly implement something, unless they are requesting your help or are working on a shared component. They could be using that time to actually implement rather than discussing it.

In the off chance that anyone actually read through this in its entirety, I hope it provides some value.

Tuesday, January 26, 2010

Error: Cannot read configuration file due to insufficient permissions – possible solution

I wanted to post an incomplete solution to this problem that I’ve encountered a couple times now.  I’m not sure the exact cause but the jist of it is that I’ve got a web site I’m hosting via IIS7 on a remote server which I can access just fine.  But when I try to host this on my local machine for debugging purposes, I get an error which resembles this when I access the page:

Server Error in '/xxxxx’ Application.

Filename: redirection.config
Error: Cannot read configuration file due to insufficient permissions

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.UnauthorizedAccessException: Filename:redirection.config
Error: Cannot read configuration file due to insufficient permissions

ASP.NET is not authorized to access the requested resource. Consider granting access rights to the resource to the ASP.NET request identity. ASP.NET has a base process identity (typically {MACHINE}\ASPNET on IIS 5 or Network Service on IIS 6) that is used if the application is not impersonating. If the application is impersonating via <identity impersonate="true"/>, the identity will be the anonymous user (typically IUSR_MACHINENAME) or the authenticated request user.

To grant ASP.NET access to a file, right-click the file in Explorer, choose "Properties" and select the Security tab. Click "Add" to add the appropriate user or group. Highlight the ASP.NET account, and check the boxes for the desired access.

The Solution:

1. Identify the user under which your web site’s application pool is running under.

2. Add this user as a User Account on your local machine and add them to the IIS_IUSRS Group (the names have been obscured to protect the innocent).

image

Sunday, January 17, 2010

Indie game developer YouTube/Vimeo channels

On one of my sister blogs, I posted a link to some independent game developer video channels.  I’ve tried to get D-Roc to make a similar video series with me, but he wouldn’t have it.  I’m convinced we could make something every bit as compelling or more (or at least have fun doing it), but alas, it wasn’t meant to be.  Maybe I’ll create my own series some day.

Tuesday, January 12, 2010

Creating a file share with a custom name – an unpleasant Windows 7 user experience

 

I usually run into this issue when I have two folders of the same name that I want to share, but I want sensible share names to distinguish them from one another.

For a concrete example, let’s suppose you have local folders on your PC called c:\project\tools and c:\development\tools (stupid names, I know).  You want to share both of these to the outside world, so you browse to c:\project, right-click the tools subfolder and click Share:

image

If everything works properly, it auto-assigns a share name of \\yourmachinename\tools.  Congrats.

But now you want to share c:\development\tools, so you follow the same process.  Here is what happens:

image

The folder is automatically shared as tools2.  Note that there is absolutely no option to choose a different name at this time.  Whether you like it or not, your folder is initially going to be shared as the name tools2.

So, now that it’s shared as tools2, you want to somehow change the share name.  To do this, you need to right-click the folder, navigate to its Sharing properties and click Advanced Sharing… (because apparently renaming a share is an advanced feature).

image

In the Advanced Sharing dialog, you’ll notice in the Settings group that it displays the current share name and lets you add additional share names.

image

What you must do is first Add a new share name (you can’t delete the existing one until you do), and give it the name you prefer (in this case, toolsdev).

image

Now you’ve got two share names for this folder, so delete the extraneous tools2 name.

image image

Now, to make matters worse, if you’ve already assigned permissions to the tools2 share, you’ll have to reassign them.  I’m not sure why this is the case.

image

Congrats!  You’ve finally created a shared folder of the name you desire, but it took about 5 steps more than it should have.