Friday, March 9, 2007

Zoom, Baby

WPF orginally got my attention because it was designed to take advantage of modern GPUs. Also, the framework includes a software-based rendering engine in case you don't have a fancy-pants graphics card in your PC. So you can do nice UI with some special graphical effects. As a bonus, animations and transformations are baked right into the framework.

The point of this blog is to find out how well WPF handles 2D games mixed in with the usual UI elements. My guess is that it will have decent performance, but still lag begind XNA or hard-core DirectX/OpenGL programming.

My theory is, the more UI your game requires, the better suited it is for WPF. Think of puzzle-type games that require lots of clicking (like Mahjong), or mystery-style games with images, video, and text. On the other hand, when there is little UI and lots of complex graphics do render, WPF just isn't going to cut it. Finaly, some games will require stupendous effects AND lots of UI (think, Supreme Commander). This last genre is best left to crazy, insane people. People who routinely eat nVidia chips with salsa to become "one with the machine".

This past week I made good progress; I learned how to stack UI elements, so that we can have a nice HUD-like display over the game board. The trick is using a <Canvas> as the top-level element under <Window>, and then adding another <Canvas> and a <Grid> as children. The <Grid> is absolutely positioned, and as long as it is the second child, will have a higher Z order than the <Canvas>, where you will stick all your sprites. You can of course set Panel.ZOrder if you want to force this.

The other neat thing is I learned how to make a zooming effect. This is useful for our game, because the game board is actually bigger than the window. When you shoot at another space ship and the shot goes off the screen, we want to allow it to loop back around if gravity is strong enough. Therefore, I wanted to zoom out to follow the shot.

At first I thought I would have to somehow paint the whole scene onto one side of a plane in 3D space, then manipulate the camera to get the effect I wanted. While WPF does let you map pretty much and 2D element onto a 3D model, it is a bit of a pain. Fortunately I found a better way.

WPF has these things called Transforms that can scale, rotate, and otherwise "transform" an element. Now, the
really cool part about this is that a transform will apply not only to the element you declare it on, but also to all child elements. Really, really, really nice. The demo shows how animating a single transform on the sprite canvas zooms everything all at once.

One last thing about the demo. Everything you see is done through declarative XAML (the file size is almost entirely the fault of the pretty background image). Although the .exe does not require it, I included Window1.xaml so you could see what is going on.

I am told that huge animations like the zooming effect have much better performance when executed inside the static Rendering event on System.Windows.Media.CompositionTarget. This is probably where we will do much of our animating anyway, especially our shots.

Download the demo (requires Vista or .NET 3.0 on XP)


Rob Relyea said...

Can you please post the apps as .xbap or .applications (plus optionally a source zip file)?
I'd love to run this first...and then maybe get the source code.
Thanks, Rob
(keep up the great posts)

Kurt said...

Thanks for the feedback - I will see about releasing some source code soon. I will also work on making the demos easier to run...

AceofSpades said...

I had to laugh when I noticed that you're zooming the background and the foreground together.

It would look a lot more realistic if you just zoomed the foreground, after all, that nebula is essentially infinitely far away when compared to this distance between the camera and the foreground.