Wednesday, December 5, 2012
Introducing Mojo
Wednesday, June 10, 2009
So according to the previous post we have defined a Control which has a name and one or more inputs it has to poll to know it's status. The messy part here is that while Microsoft has made it easy to poll a single input to know it's status, such as a game pads left shoulder button using GamePad.GetState(players[1]).Buttons.LeftShoulder() this doesn't translate well to polling a control state dynamically. The method required is very specific, but we need a way to tell a controller to pole this input specifically without wanting to go through a huge switch statement of all possible inputs every time to do it. We need a dynamic way to assign the polling method to something.
One basic way we can do this is to create an Interface which poles an input, then create an implementing Class for each input which we want to make available.
public interface InputTrigger
{
public static float getInput(GamePadState gpState);
}
public class LeftShoulderButton : InputTrigger
{
public static float getInput(GamePadState gpState)
{
return gpState.Buttons.LeftShoulder();
}
}
Than the control would only need a List<InputTrigger> initialized at startup with the right InputTrigger implementing class instances, and it could test all of its triggers by walking the list:
List<InputTrigger> inputTriggers = new List<InputTrigger>();
public void InitInput()
{
inputTriggers.Add(new LeftShoulderButton());
}
public float Pole(){
float value = 0.0f;
foreach (InputTrigger it in inputTriggers)
{
float input = it.getInput();
if (value == 0.0f)
value = input;
}
return value;
}
This works just fine, the control only has to pole the input triggers it's interested in without having to walk an entire list of all possible inputs to get the ones it wants. But it's still inefficient, we have to create a class for each input, and a class instance for each input we wish to pole. There must be a way to assign the getInput() method directly to something without needing the class surrounding it. And there is!
Most modern languages support a programming pattern called Anonymous Functions (not Methods, because Methods are a part of a class which these are not). In short Anonymous Functions allow a program to assign code to a variable dynamically at run time. In pseudo code an anonymous function would look something like this adsf
var aMethod = { return x + x; }
print aMethod( 5 );
aMethod = { return x * x; }
print aMethod( 5 );
The results of running this code would unsurprisingly be:sdf
5
25
But for strongly typed languages such as Java and C# this simple syntax wont work. Among other problems, how is the return type defined, and what defines the parameters? In version 3 of C# the languages developers solved these problems by introducing delegates. To use delegates and assign them to variables you must first define a delegate type:
delegate float TriggerType(GamePadState gpState);
This solves the problem of how to define the return type and parameters for our Anonymous Function. Once you have a type you can create variables that will hold Anonymous Functions which conform to that type:
private TriggerType triggers;
And assign code to them:
triggers = delegate(GamePadState gpState)
{
if (gpState == null || !gpState.IsConnected) return -1.0f;
if (gpState.Buttons.LeftShoulder == ButtonState.Pressed)
{
return -1.0f;
}
};
Now the control can test it's trigger by simply calling trigger(gamePadState) and it doesn't have to know anything at all about what input is being poled. But what if we have more than one trigger, do we still need to create of a List of trigger delegates? No, that's one of the cooler things (and more dangerous things) about triggers, they stack. You can add another trigger to be eveluated after the first one like this:
triggers += delegate(GamePadState gpState)
{
if (gpState == null || !gpState.IsConnected) return -1.0f;
if (gpState.Buttons.RightShoulder == ButtonState.Pressed)
{
return -1.0f;
}
};
Now both LeftShould and RightShoulder will be poled on one call to triggers(gamePadState). I call this dangerous because it's an example of hidden functionality, By simply looking at the trigger variable there is no way of knowing how many delegates will be assigned to it, or what all of them might do, this can cause unexpected behaviors that would be a pain to debug. Use with caution. There is a problem here, we will only ever see the last value returned, the test for RightShoulder, LeftShoulder results are forever hidden (another example of hidden functionality and the problems it can cause). To solve this we're going to have to pass our return value along to any fallowing triggers so that they can decide if their results are more important than results already rendered. For the purpose of this example we'll make it so that if the previous results are > 0 we'll leave them alone, but if they are 0 we'll overwrite it with our results.
The problem is there is no way I know of that a delegate can see the return value of a delegate that executed before it. So we're going to have to use a reference parameter to pass the return value. The code changes like this:
delegate void TriggerType(GamePadState gpState, ref float value);
triggers = delegate(GamePadState gpState, ref float value)
{
if (value > 0 || gpState == null || !gpState.IsConnected) return;
if (gpState.Buttons.LeftShoulder == ButtonState.Pressed)
{
value = 1;
}
};
triggers += delegate(GamePadState gpState, ref float value)
{
if (value > 0 || gpState == null || !gpState.IsConnected) return;
if (gpState.Buttons.RightShoulder == ButtonState.Pressed)
{
value = 1;
}
};
Notice the use of += on the second assignment, the new delegate is added to triggers without removing the last one. Note that C# does not guarantee in which order delegates chained like this will be executed. Now we pole our triggers by passing in a variable that will be set to the resulting value: triggers(gamePadState, ref ourValue). We'll get the value of the first pole that returns something other than 0. We only have '1' as a possible return value in these sample, but analog stick triggers can return float values between 0.0 and 1.0 and mouse triggers can return any value from 0 to the height and width of your current screen.
There's one last special case we need to deal with. Even Microsoft wasn't big on the idea of creating a poling method for each and every possible key hit on all possible international keyboards, so the poling method for them accepts a string input of what you want to pole. You can pole a keyboard key like this: keyState.IsKeyDown(“Down”). This is great, we only need one delegate to handle all possible keyboard keys and we just pass it in the Trigger value from our configuration file. We create a method to do this for us:
static TriggerType BuildKeyTriggerDelegate(Keys keyIn)
{
return delegate(KeyboardState keyState, ref float value)
{
if (keyState == null) return;
if (keyState.IsKeyDown(keyIn))
{
value = 1;
}
};
}
This exposes something particularly tricky about delegates. Notice how the keyIn parameter is never passed directly to the delegate, but the delegate uses it via the context of the BuildKeyTriggerDelegate method that creates it, and that context survives the life of the delegate! You might think that because the BuildKeyTriggerDelegate method is static multiple key trigger delegates might share the same context and collide with one another, but such is not the case, each call to BuildKeyTriggerDelegate creates it's own unique context for the delegate it builds.
There, now our initialization code can read the configuration file and build controllers with delegate trigger chains that execute quickly and efficiently. We essentially moved the huge switch statement from the runtime code to the initialization code, which is much better.
All that being said, while doing a little research for this post I found that behind the scenes the C# compiler is very likely creating wrapper classes around all our delegates anyway, so there is probably no runtime advantage between our version that created class instances for each trigger and the one with delegates. Oh well.
Tuesday, April 28, 2009
Input Wrangling Part 2
foreach (InputSettings.Trigger trigger in triggerList){ bool status; switch(trigger.inputType) { ... case "LeftShoulder": status = pgState.Buttons.LeftShoulder == ButtonState.Pressed; break; case "RightShoulder": status = pgState.Buttons.LeftShoulder == ButtonState.Pressed; break; ... } // deal with input type status conflicts here}
public abstract class InputPoll { public abstract float poll(GamePadState gpState); } public class LeftShoulder : InputPoll { public override float poll(GamePadState pgState) { return pgState.Buttons.LeftShoulder == ButtonState.Pressed ? 1.0f : 0.0f; } } public class RightShoulder : InputPoll { public override float poll(GamePadState pgState) { return pgState.Buttons.RightShoulder == ButtonState.Pressed ? 1.0f : 0.0f; } }
List<InputPoll> inputTriggers = new List<InputPoll>(); foreach (InputSettings.Trigger trigger in triggerList) { switch(trigger.Type) { case "LeftShoulder": inputTriggers.add(new RightShoulder()); break; case "RightShoulder": inputTriggers.add(new LeftShoulder()); break; } }
foreach(InputPoll inputTrigger in inputTriggers) { status = inputTrigger.poll(pgStatus); // deal with input type status conflicts here }
Wednesday, April 15, 2009
Input Wrangling Part 1
- What the value of a given control is
- What trigger(s) are effecting a given control
- What controls there are
- What triggers are available
- Which triggers will affect which controls
- How the controllers are used
- Trigger Gamepad DPadUp
- Trigger Gamepad ThumbStickLeftY
- Trigger Keyboard UpArrow
- Trigger Gamepad DpadDown
- Trigger Gamepad ThumbStickLeftY
- Trigger Keyboard DownArrow
<InputSettings> <Inputs> <Players> <Player> <Controls> <Control name="ThrustUp"> <Triggers> <Trigger controller="GamePad" value="DPadUp"/> <Trigger controller="GamePad" value="ThumbSticksLeftY"/> <Trigger controller="Key" value="Up"/> </Triggers> </Control> <Control name="ThrustDown"> <Triggers> <Trigger controller="GamePad" value="DPadDown"/> <Trigger controller="GamePad" value="ThumbSticksLeftY"/> <Trigger controller="Key" value="Down"/> </Triggers> </Control> </Controls> </Player> </Players> </Inputs></InputSettings>
<InputSettings> <Inputs> <Players> <Player> <Controls> <Control name="Play"> <Triggers> <Trigger controller="GamePad" value="A"/> <Trigger controller="GamePad" value="X"/> <Trigger controller="Key" value="Enter"/> <Trigger controller="Key" value="Space"/> <Trigger controller="Mouse" value="LeftButton"/> </Triggers> </Control> </Controls> </Player> </Players> </Inputs></InputSettings>
Wednesday, April 8, 2009
Ah, Physics!
Wednesday, April 1, 2009
Finding A Way To Make Things Fall Down
Monday, March 23, 2009
On Keeping Things Managable
Before we get started I need to do a little...
[rant]
Lets talk about project organization a little. Not code organization but where the files holding the code go. I know the standard C# starter project puts the initial code file in the root directory, and that's fine for the main code file and files for any other really important code, but when there starts to be more than 5 .cs files (or .c or .cpp or .js or whatever) in the root, it's time to get organized.
Somebody started the Spacwar game template with good intentions, there are 4 code directories in the project with 15 base classes in them. Then someone else (I'm assuming) came along to finish the project and completely ignored this organization creating 22 more source files in the root, many of them holding classes that are children of the base classes in the folders. This is the kind of thing that makes Build Masters and maintenance programmers openly weep.
Come on, it's not that hard to create a new class file in a folder or drag and drop them into a folder afterwards. It took all of 5 minutes to move all the children classes into their parent directories and create new folders for those without. Visual Studio doesn't care where the files are as long as it can find them, and you'll probably just leave them all open and use Ctrl-Tab or the Active Files drop-down to select them anyway.
A little organization, build masters and anyone who has to jump into you're project late in the game will thank you.
[/rant]
The first code I decided to tackle was the state machine that controls the screen graph used to managed which object(s) are controlling the graphics device at any given time. On start up you're in a Splash Screen state with the SplashScreen object instance being run, then after a set amount of time the SplashScreen will change the state to MainMenu and the MainMenuScreen will take over, and so on.
The sate machine used by the Spacewar template is rudimentary, without transitional states to aid in starting up and shutting down a given state. So I created a new State base class with internal STARTING_UP, RUNNING and SHUTTING_DOWN sub-states. This should aid situations where the entering or leaving of a screen isn't a single frame task, such as when you want to fade out or have a loading screen.
The screen graph itself is interesting, the main game class contains no graphics drawing code at all, though it still sets up and initializes the GraphicsDevice. Instead it passes all Update and Draw calls to an instance of a Screen extending class stored in a currentScreen variable. Thus a Screen class is like a little XNA application all on it's own, it can handle it's own input and logic and present it's own experience.
Screens can also hold an instances of another Screen in an instance variable called overlayScreen, which will be drawn after it's holding Screen and can itself have an overlayScreen. This lets you create something similar to layers in a drawing program. For example the Spacewar template project has a nice animated background of a nebula in it's Evolved game-play mode, if this had been implemented as a Screen (it wasn't) then it could have been used as a background Screen 'layer' for the evolved game-play, the main menu screen, the ship selection menu, the weapon selection menu and so on simply by making it the first Screen in the graph.
Initializing the main menu with the nebula background would look a little something like this
currentScreen = new NebulaScreen();
currentScreen.overlayScreen = new MainMenuScreen();
So the active Screen graph is simply:
NebulaScreen->MainMenuScreen
I really like this because it can greatly simplify some complex UI situations for a game, for example I'm expecting my game to use 4 layers in play mode:
GamePlayScreen->HUDScreen->PauseMenuScreen->CursorScreen
The PauseMenuScreen and the CursorScreen will be inactive during normal play but easy to 'switch on' when the game pauses, with the game play still visible in the background, and I plan to be able to reuse them both for other menus in the program.
I changed the game classes “Screen currentScreen;” variable into “List<Screen>
Note that if you're having different Screens rendering 3D objects then which object is drawn 'in front' of another is up to the GraphicsDevices' depth buffer and not the draw order. So things drawn on a different 'layer' as I've been calling them can still show up behind things drawn earlier if they are at a deeper depth in the buffer.
Next up: In which I pick a physics engine and try to get something 3D on the screen, running headlong into Spacewars 'simple' shader while stumbling around in the dark (or to be more accurate, in the cornflower blue).