|
Written by Markus Ewald
|
|
Thursday, December 09 2010 12:03 |
|
There has been a discussion on the XNA forums regarding a slight decrease in the visual quality
of SpriteFonts from XNA 3.1 to XNA 4.0: XNA 4.0 renders SpriteFont
differently (and not for the better).
There are two changes that might have impacted visual quality: XNA 4.0 uses premultiplied
alpha everywhere (whereas XNA 3.1 processed the alpha channel as-is) and, as revealed by
"Krome Studios", The FontDescriptionProcessor in XNA 4.0 generates
a texture with DXT3 (a form of compression that limits each block of 4x4 pixels to contain
only 4 different colors and reduces the alpha channel to 4 bits of precision or 16 levels,
see Wikipedia).
Because I've written a custom FontDescriptionProcessor for XNA 4.0 which outputs compatible
SpriteFonts but uses FreeType instead of Windows' GDI font
API, I decided to do a little comparison.
Read on for the results!
|
|
Written by Markus Ewald
|
|
Saturday, November 06 2010 14:56 |
|
More than a year ago, I did some benchmarking in XNA 3.1, comparing the vertex throughput I could
achieve on my GeForce 8800 via XNA's DynamicVertexBuffer
class versus just calling GraphicsDevice.DrawUserPrimitives().
Here's my earlier benchmark: Efficiently
Rendering Dynamic Vertices.
In all cases, DrawUserPrimitives() was marginally faster than the DynmicVertexBuffer, but it appeared
to be a very bad idea to use a DynamicVertexBuffer on the Xbox 360. I had a really nice
discussion with Shawn Hargreaves on the XNA forums where he provided a lot of in-depth information
about how things work on the Xbox 360: .
One of today's threads on
the AppHub forums reminded me if my earlier benchmarks, so I decided to dig out my old benchmark
and redo it in XNA 4.0. The benchmark uses my Nuclex Framework's PrimitiveBatch class,
which underwent some changes since then, so I repeated the XNA 3.1 benchmarks in addition to
getting the new data for XNA 4.0.
|
|
Written by Markus Ewald
|
|
Thursday, September 30 2010 14:16 |
|
Proponents of dependency injection try to design classes so they can either
work autonomously or get all services they rely on handed to them through
their constructor. But even without dependency injection, the situation often
arises where certain classes need to interact with a lot of other objects.
In these cases, you often end up with very complicated constructors and
a lot of duplicate code:
public class RadarBuildingRenderer {
public RadarBuildingRenderer(
ISceneGraph sceneGraph,
IContentManager contentManager,
IAudioManager audioManager,
RadarBuilding building
) {
this.sceneGraph = sceneGraph;
this.contentManager = contentManager;
this.audioManager = audioManager;
this.building = building;
}
private ISceneGraph sceneGraph;
private IContentManager contentManager;
private IAudioManager audioManager;
private RadarBuilding building;
}
Above class takes care of rendering the visual and audible representations
of a RadarBuilding in a computer game. As you can imagine,
the same references will be required by other buildings, think
TankFactoryBuilding, CommandCenterBuilding and so
on - all duplicating the fields, their assignment and the complex constructor.
|
|
Written by Markus Ewald
|
|
Wednesday, September 15 2010 11:48 |
|
There are lots of small tricks a programmer learns over time. With this
post, I'm starting a little column called Code Better in which
I'll share some of my own tricks! If you want to show off some useful
tricks of your own, I'd be happy to publish them here, too :)
The first trick is a simple technique to make complicated if statements
more readable. Let's take a look at this beast:
// Only access the height field if the position is within
if(
(x >= 0) && (y >= 0) &&
(x < this.heightField.Width) &&
(y < this.heightField.Length)
) {
return this.heightField[x, y];
} else { // Position is outside the height field
return 0.0f;
}
The code isn't unreadable per se, but it takes more than a glance to
understand what's going on. The comments help, but there's a more
elegant way that makes those comments entirely redundant:
bool isInsideHeightField =
(x >= 0) &&
(y >= 0) &&
(x < this.heightField.Width) &&
(y < this.heightField.Length);
if(isInsideHeightField) {
return this.heightField[x, y];
} else {
return 0.0f;
}
The beauty in this is that the first thing you see is
bool isInsideHeightField, prominently positioned
at one indent less than the conditions. Your brain registers
the purpose of that block of code before it encounters the actual code.
The if below is also much more obvious. If the position
is inside the height field, look up the value in the height field,
otherwise return zero. Almost like reading english.
Finally, this level of obviousness eliminates the need for any
additional comments in the code!
|
|
Written by Markus Ewald
|
|
Monday, September 13 2010 14:04 |
|
In the game I'm currently working on, it appears that I'm slowly drifting
towards a design that's a close resemblance of the Model-View-Controller
(MVC) pattern, despite originally rejecting the idea because I
believed it would require my game world to expose too much of its
internal data just so the view could keep track of things.
Because I originally believed to be building a very simple game with very
simple logic, I chose a design that would create a nice, non-fractured
interface to the world so I would have an easier time building the AI
and player controls on top of it:
In this design, everything could access everything else - a monolithic
world component where the public interface was well encapsulated,
but that allowed the implementation to take the most direct path possible.
"Everything could access everything else" doesn't mean my
objects directly modified each other's state, but it meant, for example, that
a building had a reference to the island it was placed on and that it could
call an internal method in the Island class to inform it when
the building was destroyed or moved.
A full design, in contrast, would give the buildings an interface through which
they determined properties about the ground (is it too rough? underwater?) and
some events so its owner would know when the building was destroyed.
If I had only taken game logic into account, this all would have worked out
very well. But there were some things that added a lot of complexity...
|
|
Written by Markus Ewald
|
|
Thursday, September 02 2010 09:40 |
|
I have updated my input library to a level where I think I can release it
into the Nuclex Framework now. The design was tailored to make
the input manager mockable (replaceable with a dummy object for
unit testing), but the effort of mocking the entire input manager (versus
just one input device) on an ad hoc basis was a bit too high (or too
unreadable when using a dynamic mock object library).
So the final revision has mocked input devices and a matching input
manager built in:
|
|
Written by Markus Ewald
|
|
Tuesday, August 17 2010 18:08 |
|
I've spent some time thinking about how input is handled
by my GUI library. One issue I didn't cover in its initial design
is that people might want to use the GUI library at the same time
as their game is running (think of a command palette in a strategy
game). I've already got some requests on the CodePlex forums
(How
to determine if a screen-position (i.e. mouseclick) is on any gui-control ?
and Unfocusing
from GUI) and it's about time I did something about this.
In the old design, an IInputReceiver was fed by one of
two classes: one was the XnaInputCapturer which relied
completely on XNA's input device classes (Keyboard,
Mouse,
GamePad)
to track the status of any input devices, the other was the
WindowInputCapturer which intercepted incoming window
message for XNA's main window to obtain the status of input devices:
This wasn't even nearly an ideal solution because now I would have
to copy & paste the game pad polling code from the
XnaInputCapturer to the WindowInputCapturer
if I wanted game pad input on Windows. The new design should fix this,
but still follow the concept of routing all input through a single
interface (IInputReceiver) to allow users to easily
attach the GUI to their own input handling code.
|
|
Written by Markus Ewald
|
|
Friday, August 13 2010 13:02 |
|
...that my artillery turret could have some issues with its scale!
|
|
Written by Markus Ewald
|
|
Friday, August 13 2010 11:50 |
|
XNA provides a neat little system for you to organize your
game's different parts in: GameComponents.
You can use them to modularize your game's subsystems,
eg. have a GuiComponent, PhysicsComponent,
SceneGraphComponent etc. so you avoid having all that
code in your Game class, or can use them for your actual
game objects in smaller games.
However, the GameComponent and
DrawableGameComponent classes provided
by XNA force you to reference the Game
class. This is unfortunate if you want to use those components
in a WinForms-based XNA application and gets in the way
when you try to write unit tests for your components because
now you have to create a dummy Game
instance as well (and better hope that component won't
go shopping for references in the Game's
Components and Services
collections as well).
Luckily, the GameComponentCollection
used by XNA to store your components manages
IGameComponents
and updating/drawing are based on the IUpdateable
and IDrawable
interfaces alone, so there's nothing preventing you from rolling your
own components without referencing the Game class.
|
|
Written by Markus Ewald
|
|
Wednesday, August 11 2010 13:31 |
|
First, let me say sorry if I seemed to be absent for the past months. I was quite burned
out and didn't want to do much with computers during that time :)
My "XNA Game Architecture" series was left hanging, and right when it got interesting, too.
I'll try to find the time to continue where I left off. For now, here's a small appetizer:
Some weeks ago, Synapse Gaming offered their
SunBurn Lighting and Rendering
Engine for half the price. This was to good an offer to pass and so I now find myself
being able to do much better lighting effects than I had ever hoped to achieve in my game.
The first thing I did was, of course, to adapt SunBurn to Ninject, a very tidy
dependency injector that works on the XBox 360 and even on Windows Phone 7,
into the SunBurn example application. This article gives a short overview about
the overall structure and provides you with an example application if you want to
give Ninject a try yourself.
|
|