It has been a long time since the last blog post , more than a month I guess eh? OK I was planning to write this for a long time now, it’s an old project where I tried to imitate camera usage of the famous and beloved platform game Fez. It’ll probably be a short post, some general guidelines and a sample project. Here we go , first of all;
What is Fez?
Fez is an adorable platform / puzzle game for XBox 360 ( supposed to be released in Q4 2011 as far as I know ). I found out about it only a few months ago when someone posted a gameplay video from PAX East 2011 on forums.
What makes it special is the usage of orthogonal camera and a great mix of 2D/3D world. Also as you can see at the 2:15 minute mark, it has pretty nice puzzles using this 2D/3D world.
I fall in love with the game the second I saw this video and decided to give it a shot to create a Fez Clone. The main idea ( and what I’ll be talking about this post ) was just imitating camera usage, orthogonal camera and cool animations for switching dimensions but then I got carried away and added a lot more to it. ( see Fedora )
So what is Orthogonal View / Projection ?
Orthogonal projection is literally means representing a three dimensional world just in 2 dimensions. This is exactly what Fez did right? Losing the 3rd dimension means no depth so you can’t really say if the actual world is 2D or 3D until the camera rotates.
Orthogonal projection yields pretty nice results and I honestly believe it’s under used in gaming industry, especially in indie games. There are possible lots and lots of new and unexplored game mechanics one can achieve using orthogonal projection.
So what is the plan?
The plan is making a simple grid based 3D world first, Fez uses a pretty similar world structure after all. I won’t go deep into this really as creating a grid world shouldn’t be hard and the code is all in sample anyway. We don’t need anything complex either, something simple like this should do it ;
And then obviously we need to create and place an orthogonal camera.
CurrentCameraPosition = new Vector3(0, 0, CamDistance);
_lookPosition = new Vector3(0, 0, 0);
ViewMatrix = Matrix.CreateLookAt(CurrentCameraPosition, _lookPosition, new Vector3(0, 1, 0));
ProjectionMatrix = Matrix.CreateOrthographicOffCenter(–400, 400, –240, 240, 0.2f, 5500.0f);
Now let’s have a look at it ;
CurrentCameraPosition is a Vector3 with x = 0 and y = 0. This means our orthogonal camera will be set on Z dimension. Also it doesn’t matter if the CamDistance is 1 or 1000 as I said before, there is no depth in orthogonal projection anyway. Only thing matters is if it’s positive or negative.
_lookPosition is obviously where it looks. Our camera will be rotating around the center.
There is nothing fancy about View Matrix, it’s just using the previous variable we created.
And projection matrix is where we decide what kind of projection we will use ( perspective or orthogonal ). Obviously we use orthogonal projection ( CreateOrthographicOffCenter ) and set some variable about the camera size. ( now we could also used CreateOrthographic method to create this but I prefer OffCenter method as it gives more flexibility. There isn’t much difference between them except that )
So now we should have a view like this;
See how there is no feeling of depth and those crates looks like they are stacked on each other?
One last thing we have to do is adding transition animations. It’s kind of hard to explain it all here so I’ll just talk about the general outline. It’s all in sample code anyway.
So we have 4 different possible camera position right? ( +x , –x , +z, –z ) This means we have 8 possible different transitions ( clockwise and counter clockwise ). So what we have to do is just interpolate camera position from , let’s say +z to +x slowly.
We will have to keep track of some stuff though like , if we’re in the middle of an animation or what’s the starting and ending points of this animation and what’s the current progress of this animation.
Leaving little stuff like those aside , this is the main transition function we will use;
_rotationTime += gameTime.ElapsedGameTime.Milliseconds / ( RotationTimeTotal * 1000 );
_rotationTime = MathHelper.Clamp(_rotationTime, 0.0f, 1.0f);
_rotationAngle = MathHelper.SmoothStep(0, 90, _rotationTime);
var _cameraRotatedPosition = Vector3.Transform(AnimationStart.CameraPosition, Matrix.CreateRotationY(MathHelper.ToRadians(_rotationAngle * ((AnimationEnd.Previous == AnimationStart) ? 1 : –1) )));
_cameraRotatedPosition += _lookPosition;
ViewMatrix = Matrix.CreateLookAt(_cameraRotatedPosition, _lookPosition, new Vector3(0, 1, 0));
It uses “_rotationTime” as an progress indicator. And we have a _rotationTimeTotal as we want all our animations to take exact same amount of time.
Then we calculate the angle we should rotate cam this iteration ( remember this block runs like hundreds of times for each animation , actually that’s something you can ( or maybe even should ) improve. Instead of calculating every single iteration, you may want to only calculate every 2 degree or something. The performance difference will be incredibly small but still that’s a more elegant approach )
Now that we have the angle, we’ll transform current camera position using that angle.
And finally set new View Matrix and keep doing this till we reach the point we need.
Notice that this function has 2 important points ; every animation should take same amount of time and camera position interpolation should be smooth ( I used SmoothStep for this one but of course you can switch to Lerp if you want to)
And this is pretty much how it should look while rotating ;
Now I know it doesn’t look that good in this screenshot but this sample is all about animation anyway and I’m sure it’ll look WAY better if you use a variety of textures for blocks etc.
You can find extra stuff I’ve done on this structure here in my Fedora Project page. There are few interesting additions like Bastion-lie world creation where objects fall from sky ( or floor rise from below ) as you move etc. All in all it was a fun project ( and actually Fedora was my XNA learning project ) but I’m not working on this anymore.
Hope you guys like it or find it useful. You can find the sample solution below, see you next time!
Visual Studio 2010 Solution