axiosengine 

axiosengine Commit Details


Date:2012-04-12 22:20:50 (12 years 6 months ago)
Author:nathan@daedalus
Branch:master
Commit:a93df07c6ed6fe642607e9b1f6c1113a4ffc5917
Parents: 4057123b6e00212e0ecb590cffbe424bcb2f8a1c
Message:Adding supporting files

--HG--
branch : axios-newgsm
Changes:

File differences

axios/ScreenSystem/Button.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
#region File Description
//-----------------------------------------------------------------------------
// Button.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
using GameStateManagement;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace GameStateManagement
{
/// <summary>
/// A special button that handles toggling between "On" and "Off"
/// </summary>
class BooleanButton : Button
{
private string option;
private bool value;
/// <summary>
/// Creates a new BooleanButton.
/// </summary>
/// <param name="option">The string text to display for the option.</param>
/// <param name="value">The initial value of the button.</param>
public BooleanButton(string option, bool value)
: base(option)
{
this.option = option;
this.value = value;
GenerateText();
}
protected override void OnTapped()
{
// When tapped we need to toggle the value and regenerate the text
value = !value;
GenerateText();
base.OnTapped();
}
/// <summary>
/// Helper that generates the actual Text value the base class uses for drawing.
/// </summary>
private void GenerateText()
{
Text = string.Format("{0}: {1}", option, value ? "On" : "Off");
}
}
/// <summary>
/// Represents a touchable button.
/// </summary>
class Button
{
/// <summary>
/// The text displayed in the button.
/// </summary>
public string Text = "Button";
/// <summary>
/// The position of the top-left corner of the button.
/// </summary>
public Vector2 Position = Vector2.Zero;
/// <summary>
/// The size of the button.
/// </summary>
public Vector2 Size = new Vector2(250, 75);
/// <summary>
/// The thickness of the border drawn for the button.
/// </summary>
public int BorderThickness = 4;
/// <summary>
/// The color of the button border.
/// </summary>
public Color BorderColor = new Color(200, 200, 200);
/// <summary>
/// The color of the button background.
/// </summary>
public Color FillColor = new Color(100, 100, 100) * .75f;
/// <summary>
/// The color of the text.
/// </summary>
public Color TextColor = Color.White;
/// <summary>
/// The opacity of the button.
/// </summary>
public float Alpha = 0f;
/// <summary>
/// Invoked when the button is tapped.
/// </summary>
public event EventHandler<EventArgs> Tapped;
/// <summary>
/// Creates a new Button.
/// </summary>
/// <param name="text">The text to display in the button.</param>
public Button(string text)
{
Text = text;
}
/// <summary>
/// Invokes the Tapped event and allows subclasses to perform actions when tapped.
/// </summary>
protected virtual void OnTapped()
{
if (Tapped != null)
Tapped(this, EventArgs.Empty);
}
/// <summary>
/// Passes a tap location to the button for handling.
/// </summary>
/// <param name="tap">The location of the tap.</param>
/// <returns>True if the button was tapped, false otherwise.</returns>
public bool HandleTap(Vector2 tap)
{
if (tap.X >= Position.X &&
tap.Y >= Position.Y &&
tap.X <= Position.X + Size.X &&
tap.Y <= Position.Y + Size.Y)
{
OnTapped();
return true;
}
return false;
}
/// <summary>
/// Draws the button
/// </summary>
/// <param name="screen">The screen drawing the button</param>
public void Draw(GameScreen screen)
{
// Grab some common items from the ScreenManager
SpriteBatch spriteBatch = screen.ScreenManager.SpriteBatch;
SpriteFont font = screen.ScreenManager.Font;
Texture2D blank = screen.ScreenManager.BlankTexture;
// Compute the button's rectangle
Rectangle r = new Rectangle(
(int)Position.X,
(int)Position.Y,
(int)Size.X,
(int)Size.Y);
// Fill the button
spriteBatch.Draw(blank, r, FillColor * Alpha);
// Draw the border
spriteBatch.Draw(
blank,
new Rectangle(r.Left, r.Top, r.Width, BorderThickness),
BorderColor * Alpha);
spriteBatch.Draw(
blank,
new Rectangle(r.Left, r.Top, BorderThickness, r.Height),
BorderColor * Alpha);
spriteBatch.Draw(
blank,
new Rectangle(r.Right - BorderThickness, r.Top, BorderThickness, r.Height),
BorderColor * Alpha);
spriteBatch.Draw(
blank,
new Rectangle(r.Left, r.Bottom - BorderThickness, r.Width, BorderThickness),
BorderColor * Alpha);
// Draw the text centered in the button
Vector2 textSize = font.MeasureString(Text);
Vector2 textPosition = new Vector2(r.Center.X, r.Center.Y) - textSize / 2f;
textPosition.X = (int)textPosition.X;
textPosition.Y = (int)textPosition.Y;
spriteBatch.DrawString(font, Text, textPosition, TextColor * Alpha);
}
}
}
axios/ScreenSystem/GameplayScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using GameStateManagement;
#endregion
namespace GameStateManagementSample
{
/// <summary>
/// This screen implements the actual game logic. It is just a
/// placeholder to get the idea across: you'll probably want to
/// put some more interesting gameplay in here!
/// </summary>
class GameplayScreen : GameScreen
{
#region Fields
ContentManager content;
SpriteFont gameFont;
Vector2 playerPosition = new Vector2(100, 100);
Vector2 enemyPosition = new Vector2(100, 100);
Random random = new Random();
float pauseAlpha;
InputAction pauseAction;
#endregion
#region Initialization
/// <summary>
/// Constructor.
/// </summary>
public GameplayScreen()
{
TransitionOnTime = TimeSpan.FromSeconds(1.5);
TransitionOffTime = TimeSpan.FromSeconds(0.5);
pauseAction = new InputAction(
new Buttons[] { Buttons.Start, Buttons.Back },
new Keys[] { Keys.Escape },
true);
}
/// <summary>
/// Load graphics content for the game.
/// </summary>
public override void Activate(bool instancePreserved)
{
if (!instancePreserved)
{
if (content == null)
content = new ContentManager(ScreenManager.Game.Services, "Content");
gameFont = content.Load<SpriteFont>("gamefont");
// A real game would probably have more content than this sample, so
// it would take longer to load. We simulate that by delaying for a
// while, giving you a chance to admire the beautiful loading screen.
Thread.Sleep(1000);
// once the load has finished, we use ResetElapsedTime to tell the game's
// timing mechanism that we have just finished a very long frame, and that
// it should not try to catch up.
ScreenManager.Game.ResetElapsedTime();
}
#if WINDOWS_PHONE
if (Microsoft.Phone.Shell.PhoneApplicationService.Current.State.ContainsKey("PlayerPosition"))
{
playerPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"];
enemyPosition = (Vector2)Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"];
}
#endif
}
public override void Deactivate()
{
#if WINDOWS_PHONE
Microsoft.Phone.Shell.PhoneApplicationService.Current.State["PlayerPosition"] = playerPosition;
Microsoft.Phone.Shell.PhoneApplicationService.Current.State["EnemyPosition"] = enemyPosition;
#endif
base.Deactivate();
}
/// <summary>
/// Unload graphics content used by the game.
/// </summary>
public override void Unload()
{
content.Unload();
#if WINDOWS_PHONE
Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("PlayerPosition");
Microsoft.Phone.Shell.PhoneApplicationService.Current.State.Remove("EnemyPosition");
#endif
}
#endregion
#region Update and Draw
/// <summary>
/// Updates the state of the game. This method checks the GameScreen.IsActive
/// property, so the game will stop updating when the pause menu is active,
/// or if you tab away to a different application.
/// </summary>
public override void Update(GameTime gameTime, bool otherScreenHasFocus,
bool coveredByOtherScreen)
{
base.Update(gameTime, otherScreenHasFocus, false);
// Gradually fade in or out depending on whether we are covered by the pause screen.
if (coveredByOtherScreen)
pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
else
pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);
if (IsActive)
{
// Apply some random jitter to make the enemy move around.
const float randomization = 10;
enemyPosition.X += (float)(random.NextDouble() - 0.5) * randomization;
enemyPosition.Y += (float)(random.NextDouble() - 0.5) * randomization;
// Apply a stabilizing force to stop the enemy moving off the screen.
Vector2 targetPosition = new Vector2(
ScreenManager.GraphicsDevice.Viewport.Width / 2 - gameFont.MeasureString("Insert Gameplay Here").X / 2,
200);
enemyPosition = Vector2.Lerp(enemyPosition, targetPosition, 0.05f);
// TODO: this game isn't very fun! You could probably improve
// it by inserting something more interesting in this space :-)
}
}
/// <summary>
/// Lets the game respond to player input. Unlike the Update method,
/// this will only be called when the gameplay screen is active.
/// </summary>
public override void HandleInput(GameTime gameTime, InputState input)
{
if (input == null)
throw new ArgumentNullException("input");
// Look up inputs for the active player profile.
int playerIndex = (int)ControllingPlayer.Value;
KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];
// The game pauses either if the user presses the pause button, or if
// they unplug the active gamepad. This requires us to keep track of
// whether a gamepad was ever plugged in, because we don't want to pause
// on PC if they are playing with a keyboard and have no gamepad at all!
bool gamePadDisconnected = !gamePadState.IsConnected &&
input.GamePadWasConnected[playerIndex];
PlayerIndex player;
if (pauseAction.Evaluate(input, ControllingPlayer, out player) || gamePadDisconnected)
{
#if WINDOWS_PHONE
ScreenManager.AddScreen(new PhonePauseScreen(), ControllingPlayer);
#else
ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
#endif
}
else
{
// Otherwise move the player position.
Vector2 movement = Vector2.Zero;
if (keyboardState.IsKeyDown(Keys.Left))
movement.X--;
if (keyboardState.IsKeyDown(Keys.Right))
movement.X++;
if (keyboardState.IsKeyDown(Keys.Up))
movement.Y--;
if (keyboardState.IsKeyDown(Keys.Down))
movement.Y++;
Vector2 thumbstick = gamePadState.ThumbSticks.Left;
movement.X += thumbstick.X;
movement.Y -= thumbstick.Y;
if (input.TouchState.Count > 0)
{
Vector2 touchPosition = input.TouchState[0].Position;
Vector2 direction = touchPosition - playerPosition;
direction.Normalize();
movement += direction;
}
if (movement.Length() > 1)
movement.Normalize();
playerPosition += movement * 8f;
}
}
/// <summary>
/// Draws the gameplay screen.
/// </summary>
public override void Draw(GameTime gameTime)
{
// This game has a blue background. Why? Because!
ScreenManager.GraphicsDevice.Clear(ClearOptions.Target,
Color.CornflowerBlue, 0, 0);
// Our player and enemy are both actually just text strings.
SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
spriteBatch.Begin();
spriteBatch.DrawString(gameFont, "// TODO", playerPosition, Color.Green);
spriteBatch.DrawString(gameFont, "Insert Gameplay Here",
enemyPosition, Color.DarkRed);
spriteBatch.End();
// If the game is transitioning on or off, fade it out to black.
if (TransitionPosition > 0 || pauseAlpha > 0)
{
float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);
ScreenManager.FadeBackBufferToBlack(alpha);
}
}
#endregion
}
}
axios/ScreenSystem/IScreenFactory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#region File Description
//-----------------------------------------------------------------------------
// IScreenFactory.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
namespace GameStateManagement
{
/// <summary>
/// Defines an object that can create a screen when given its type.
///
/// The ScreenManager attempts to handle tombstoning on Windows Phone by creating an XML
/// document that has a list of the screens currently in the manager. When the game is
/// reactivated, the ScreenManager needs to create instances of those screens. However
/// since there is no restriction that a particular GameScreen subclass has a parameterless
/// constructor, there is no way the ScreenManager alone could create those instances.
///
/// IScreenFactory fills this gap by providing an interface the game should implement to
/// act as a translation from type to instance. The ScreenManager locates the IScreenFactory
/// from the Game.Services collection and passes each screen type to the factory, expecting
/// to get the correct GameScreen out.
///
/// If your game screens all have parameterless constructors, the minimal implementation of
/// this interface would look like this:
///
/// return Activator.CreateInstance(screenType) as GameScreen;
///
/// If you have screens with constructors that take arguments, you will need to ensure that
/// you can read these arguments from storage or generate new ones, then construct the screen
/// based on the type.
///
/// The ScreenFactory type in the sample game has the minimal implementation along with some
/// extra comments showing a potentially more complex example of how to implement IScreenFactory.
/// </summary>
public interface IScreenFactory
{
/// <summary>
/// Creates a GameScreen from the given type.
/// </summary>
/// <param name="screenType">The type of screen to create.</param>
/// <returns>The newly created screen.</returns>
GameScreen CreateScreen(Type screenType);
}
}
axios/ScreenSystem/InputAction.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#region File Description
//-----------------------------------------------------------------------------
// InputAction.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
namespace GameStateManagement
{
/// <summary>
/// Defines an action that is designated by some set of buttons and/or keys.
///
/// The way actions work is that you define a set of buttons and keys that trigger the action. You can
/// then evaluate the action against an InputState which will test to see if any of the buttons or keys
/// are pressed by a player. You can also set a flag that indicates if the action only occurs once when
/// the buttons/keys are first pressed or whether the action should occur each frame.
///
/// Using this InputAction class means that you can configure new actions based on keys and buttons
/// without having to directly modify the InputState type. This means more customization by your games
/// without having to change the core classes of Game State Management.
/// </summary>
public class InputAction
{
private readonly Buttons[] buttons;
private readonly Keys[] keys;
private readonly bool newPressOnly;
// These delegate types map to the methods on InputState. We use these to simplify the evalute method
// by allowing us to map the appropriate delegates and invoke them, rather than having two separate code paths.
private delegate bool ButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex player);
private delegate bool KeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex player);
/// <summary>
/// Initializes a new InputAction.
/// </summary>
/// <param name="buttons">An array of buttons that can trigger the action.</param>
/// <param name="keys">An array of keys that can trigger the action.</param>
/// <param name="newPressOnly">Whether the action only occurs on the first press of one of the buttons/keys,
/// false if it occurs each frame one of the buttons/keys is down.</param>
public InputAction(Buttons[] buttons, Keys[] keys, bool newPressOnly)
{
// Store the buttons and keys. If the arrays are null, we create a 0 length array so we don't
// have to do null checks in the Evaluate method
this.buttons = buttons != null ? buttons.Clone() as Buttons[] : new Buttons[0];
this.keys = keys != null ? keys.Clone() as Keys[] : new Keys[0];
this.newPressOnly = newPressOnly;
}
/// <summary>
/// Evaluates the action against a given InputState.
/// </summary>
/// <param name="state">The InputState to test for the action.</param>
/// <param name="controllingPlayer">The player to test, or null to allow any player.</param>
/// <param name="player">If controllingPlayer is null, this is the player that performed the action.</param>
/// <returns>True if the action occurred, false otherwise.</returns>
public bool Evaluate(InputState state, PlayerIndex? controllingPlayer, out PlayerIndex player)
{
// Figure out which delegate methods to map from the state which takes care of our "newPressOnly" logic
ButtonPress buttonTest;
KeyPress keyTest;
if (newPressOnly)
{
buttonTest = state.IsNewButtonPress;
keyTest = state.IsNewKeyPress;
}
else
{
buttonTest = state.IsButtonPressed;
keyTest = state.IsKeyPressed;
}
// Now we simply need to invoke the appropriate methods for each button and key in our collections
foreach (Buttons button in buttons)
{
if (buttonTest(button, controllingPlayer, out player))
return true;
}
foreach (Keys key in keys)
{
if (keyTest(key, controllingPlayer, out player))
return true;
}
// If we got here, the action is not matched
player = PlayerIndex.One;
return false;
}
}
}
axios/ScreenSystem/InputState.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
#region File Description
//-----------------------------------------------------------------------------
// InputState.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using FarseerPhysics.SamplesFramework;
namespace GameStateManagement
{
/// <summary>
/// Helper for reading input from keyboard, gamepad, and touch input. This class
/// tracks both the current and previous state of the input devices, and implements
/// query methods for high level input actions such as "move up through the menu"
/// or "pause the game".
/// </summary>
public class InputState
{
public const int MaxInputs = 4;
public readonly KeyboardState[] CurrentKeyboardStates;
public readonly GamePadState[] CurrentGamePadStates;
public readonly KeyboardState[] LastKeyboardStates;
public readonly GamePadState[] LastGamePadStates;
public readonly bool[] GamePadWasConnected;
/*
* Needed for virtual stick on WP7
* -- Nathan Adams [adamsna@datanethost.net] - 4/12/2012
*/
private GamePadState _currentVirtualState;
private GamePadState _lastVirtualState;
private bool _handleVirtualStick;
/*
* I didn't create an array for the virtual stick because there will only be one
* -- Nathan Adams [adamsna@datanethost.net] - 4/12/2012
*/
/*
*
*
*
*
*
*/
private Vector2 _cursor;
private bool _cursorIsValid;
private bool _cursorIsVisible;
private bool _cursorMoved;
private Sprite _cursorSprite;
#if WINDOWS_PHONE
private VirtualStick _phoneStick;
private VirtualButton _phoneA;
private VirtualButton _phoneB;
#endif
public TouchCollection TouchState;
public readonly List<GestureSample> Gestures = new List<GestureSample>();
/// <summary>
/// Constructs a new input state.
/// </summary>
public InputState()
{
CurrentKeyboardStates = new KeyboardState[MaxInputs];
CurrentGamePadStates = new GamePadState[MaxInputs];
LastKeyboardStates = new KeyboardState[MaxInputs];
LastGamePadStates = new GamePadState[MaxInputs];
GamePadWasConnected = new bool[MaxInputs];
}
/// <summary>
/// Reads the latest state user input.
/// </summary>
public void Update()
{
for (int i = 0; i < MaxInputs; i++)
{
LastKeyboardStates[i] = CurrentKeyboardStates[i];
LastGamePadStates[i] = CurrentGamePadStates[i];
CurrentKeyboardStates[i] = Keyboard.GetState((PlayerIndex)i);
CurrentGamePadStates[i] = GamePad.GetState((PlayerIndex)i);
// Keep track of whether a gamepad has ever been
// connected, so we can detect if it is unplugged.
if (CurrentGamePadStates[i].IsConnected)
{
GamePadWasConnected[i] = true;
}
}
// Get the raw touch state from the TouchPanel
TouchState = TouchPanel.GetState();
// Read in any detected gestures into our list for the screens to later process
Gestures.Clear();
while (TouchPanel.IsGestureAvailable)
{
Gestures.Add(TouchPanel.ReadGesture());
}
}
/// <summary>
/// Helper for checking if a key was pressed during this update. The
/// controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a keypress
/// is detected, the output playerIndex reports which player pressed it.
/// </summary>
public bool IsKeyPressed(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentKeyboardStates[i].IsKeyDown(key);
}
else
{
// Accept input from any player.
return (IsKeyPressed(key, PlayerIndex.One, out playerIndex) ||
IsKeyPressed(key, PlayerIndex.Two, out playerIndex) ||
IsKeyPressed(key, PlayerIndex.Three, out playerIndex) ||
IsKeyPressed(key, PlayerIndex.Four, out playerIndex));
}
}
/// <summary>
/// Helper for checking if a button was pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// </summary>
public bool IsButtonPressed(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return CurrentGamePadStates[i].IsButtonDown(button);
}
else
{
// Accept input from any player.
return (IsButtonPressed(button, PlayerIndex.One, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Two, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Three, out playerIndex) ||
IsButtonPressed(button, PlayerIndex.Four, out playerIndex));
}
}
/// <summary>
/// Helper for checking if a key was newly pressed during this update. The
/// controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a keypress
/// is detected, the output playerIndex reports which player pressed it.
/// </summary>
public bool IsNewKeyPress(Keys key, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return (CurrentKeyboardStates[i].IsKeyDown(key) &&
LastKeyboardStates[i].IsKeyUp(key));
}
else
{
// Accept input from any player.
return (IsNewKeyPress(key, PlayerIndex.One, out playerIndex) ||
IsNewKeyPress(key, PlayerIndex.Two, out playerIndex) ||
IsNewKeyPress(key, PlayerIndex.Three, out playerIndex) ||
IsNewKeyPress(key, PlayerIndex.Four, out playerIndex));
}
}
/// <summary>
/// Helper for checking if a button was newly pressed during this update.
/// The controllingPlayer parameter specifies which player to read input for.
/// If this is null, it will accept input from any player. When a button press
/// is detected, the output playerIndex reports which player pressed it.
/// </summary>
public bool IsNewButtonPress(Buttons button, PlayerIndex? controllingPlayer, out PlayerIndex playerIndex)
{
if (controllingPlayer.HasValue)
{
// Read input from the specified player.
playerIndex = controllingPlayer.Value;
int i = (int)playerIndex;
return (CurrentGamePadStates[i].IsButtonDown(button) &&
LastGamePadStates[i].IsButtonUp(button));
}
else
{
// Accept input from any player.
return (IsNewButtonPress(button, PlayerIndex.One, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Two, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Three, out playerIndex) ||
IsNewButtonPress(button, PlayerIndex.Four, out playerIndex));
}
}
}
}
axios/ScreenSystem/LoadingScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
#region File Description
//-----------------------------------------------------------------------------
// LoadingScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using GameStateManagement;
#endregion
namespace GameStateManagement
{
/// <summary>
/// The loading screen coordinates transitions between the menu system and the
/// game itself. Normally one screen will transition off at the same time as
/// the next screen is transitioning on, but for larger transitions that can
/// take a longer time to load their data, we want the menu system to be entirely
/// gone before we start loading the game. This is done as follows:
///
/// - Tell all the existing screens to transition off.
/// - Activate a loading screen, which will transition on at the same time.
/// - The loading screen watches the state of the previous screens.
/// - When it sees they have finished transitioning off, it activates the real
/// next screen, which may take a long time to load its data. The loading
/// screen will be the only thing displayed while this load is taking place.
/// </summary>
class LoadingScreen : GameScreen
{
#region Fields
bool loadingIsSlow;
bool otherScreensAreGone;
GameScreen[] screensToLoad;
#endregion
#region Initialization
/// <summary>
/// The constructor is private: loading screens should
/// be activated via the static Load method instead.
/// </summary>
private LoadingScreen(ScreenManager screenManager, bool loadingIsSlow,
GameScreen[] screensToLoad)
{
this.loadingIsSlow = loadingIsSlow;
this.screensToLoad = screensToLoad;
TransitionOnTime = TimeSpan.FromSeconds(0.5);
}
/// <summary>
/// Activates the loading screen.
/// </summary>
public static void Load(ScreenManager screenManager, bool loadingIsSlow,
PlayerIndex? controllingPlayer,
params GameScreen[] screensToLoad)
{
// Tell all the current screens to transition off.
foreach (GameScreen screen in screenManager.GetScreens())
screen.ExitScreen();
// Create and activate the loading screen.
LoadingScreen loadingScreen = new LoadingScreen(screenManager,
loadingIsSlow,
screensToLoad);
screenManager.AddScreen(loadingScreen, controllingPlayer);
}
#endregion
#region Update and Draw
/// <summary>
/// Updates the loading screen.
/// </summary>
public override void Update(GameTime gameTime, bool otherScreenHasFocus,
bool coveredByOtherScreen)
{
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
// If all the previous screens have finished transitioning
// off, it is time to actually perform the load.
if (otherScreensAreGone)
{
ScreenManager.RemoveScreen(this);
foreach (GameScreen screen in screensToLoad)
{
if (screen != null)
{
ScreenManager.AddScreen(screen, ControllingPlayer);
}
}
// Once the load has finished, we use ResetElapsedTime to tell
// the game timing mechanism that we have just finished a very
// long frame, and that it should not try to catch up.
ScreenManager.Game.ResetElapsedTime();
}
}
/// <summary>
/// Draws the loading screen.
/// </summary>
public override void Draw(GameTime gameTime)
{
// If we are the only active screen, that means all the previous screens
// must have finished transitioning off. We check for this in the Draw
// method, rather than in Update, because it isn't enough just for the
// screens to be gone: in order for the transition to look good we must
// have actually drawn a frame without them before we perform the load.
if ((ScreenState == ScreenState.Active) &&
(ScreenManager.GetScreens().Length == 1))
{
otherScreensAreGone = true;
}
// The gameplay screen takes a while to load, so we display a loading
// message while that is going on, but the menus load very quickly, and
// it would look silly if we flashed this up for just a fraction of a
// second while returning from the game to the menus. This parameter
// tells us how long the loading is going to take, so we know whether
// to bother drawing the message.
if (loadingIsSlow)
{
SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
SpriteFont font = ScreenManager.Font;
const string message = "Loading...";
// Center the text in the viewport.
Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
Vector2 viewportSize = new Vector2(viewport.Width, viewport.Height);
Vector2 textSize = font.MeasureString(message);
Vector2 textPosition = (viewportSize - textSize) / 2;
Color color = Color.White * TransitionAlpha;
// Draw the text.
spriteBatch.Begin();
spriteBatch.DrawString(font, message, textPosition, color);
spriteBatch.End();
}
}
#endregion
}
}
axios/ScreenSystem/MainMenuScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#region File Description
//-----------------------------------------------------------------------------
// MainMenuScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using Microsoft.Xna.Framework;
#endregion
namespace GameStateManagement
{
/// <summary>
/// The main menu screen is the first thing displayed when the game starts up.
/// </summary>
class MainMenuScreen : MenuScreen
{
#region Initialization
/// <summary>
/// Constructor fills in the menu contents.
/// </summary>
public MainMenuScreen()
: base("Main Menu")
{
// Create our menu entries.
MenuEntry playGameMenuEntry = new MenuEntry("Play Game");
MenuEntry optionsMenuEntry = new MenuEntry("Options");
MenuEntry exitMenuEntry = new MenuEntry("Exit");
// Hook up menu event handlers.
playGameMenuEntry.Selected += PlayGameMenuEntrySelected;
optionsMenuEntry.Selected += OptionsMenuEntrySelected;
exitMenuEntry.Selected += OnCancel;
// Add entries to the menu.
MenuEntries.Add(playGameMenuEntry);
MenuEntries.Add(optionsMenuEntry);
MenuEntries.Add(exitMenuEntry);
}
#endregion
#region Handle Input
/// <summary>
/// Event handler for when the Play Game menu entry is selected.
/// </summary>
void PlayGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
LoadingScreen.Load(ScreenManager, true, e.PlayerIndex,
new GameplayScreen());
}
/// <summary>
/// Event handler for when the Options menu entry is selected.
/// </summary>
void OptionsMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
ScreenManager.AddScreen(new OptionsMenuScreen(), e.PlayerIndex);
}
/// <summary>
/// When the user cancels the main menu, ask if they want to exit the sample.
/// </summary>
protected override void OnCancel(PlayerIndex playerIndex)
{
const string message = "Are you sure you want to exit this sample?";
MessageBoxScreen confirmExitMessageBox = new MessageBoxScreen(message);
confirmExitMessageBox.Accepted += ConfirmExitMessageBoxAccepted;
ScreenManager.AddScreen(confirmExitMessageBox, playerIndex);
}
/// <summary>
/// Event handler for when the user selects ok on the "are you sure
/// you want to exit" message box.
/// </summary>
void ConfirmExitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
{
ScreenManager.Game.Exit();
}
#endregion
}
}
axios/ScreenSystem/OptionsMenuScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#region File Description
//-----------------------------------------------------------------------------
// OptionsMenuScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using Microsoft.Xna.Framework;
#endregion
namespace GameStateManagement
{
/// <summary>
/// The options screen is brought up over the top of the main menu
/// screen, and gives the user a chance to configure the game
/// in various hopefully useful ways.
/// </summary>
class OptionsMenuScreen : MenuScreen
{
#region Fields
MenuEntry ungulateMenuEntry;
MenuEntry languageMenuEntry;
MenuEntry frobnicateMenuEntry;
MenuEntry elfMenuEntry;
enum Ungulate
{
BactrianCamel,
Dromedary,
Llama,
}
static Ungulate currentUngulate = Ungulate.Dromedary;
static string[] languages = { "C#", "French", "Deoxyribonucleic acid" };
static int currentLanguage = 0;
static bool frobnicate = true;
static int elf = 23;
#endregion
#region Initialization
/// <summary>
/// Constructor.
/// </summary>
public OptionsMenuScreen()
: base("Options")
{
// Create our menu entries.
ungulateMenuEntry = new MenuEntry(string.Empty);
languageMenuEntry = new MenuEntry(string.Empty);
frobnicateMenuEntry = new MenuEntry(string.Empty);
elfMenuEntry = new MenuEntry(string.Empty);
SetMenuEntryText();
MenuEntry back = new MenuEntry("Back");
// Hook up menu event handlers.
ungulateMenuEntry.Selected += UngulateMenuEntrySelected;
languageMenuEntry.Selected += LanguageMenuEntrySelected;
frobnicateMenuEntry.Selected += FrobnicateMenuEntrySelected;
elfMenuEntry.Selected += ElfMenuEntrySelected;
back.Selected += OnCancel;
// Add entries to the menu.
MenuEntries.Add(ungulateMenuEntry);
MenuEntries.Add(languageMenuEntry);
MenuEntries.Add(frobnicateMenuEntry);
MenuEntries.Add(elfMenuEntry);
MenuEntries.Add(back);
}
/// <summary>
/// Fills in the latest values for the options screen menu text.
/// </summary>
void SetMenuEntryText()
{
ungulateMenuEntry.Text = "Preferred ungulate: " + currentUngulate;
languageMenuEntry.Text = "Language: " + languages[currentLanguage];
frobnicateMenuEntry.Text = "Frobnicate: " + (frobnicate ? "on" : "off");
elfMenuEntry.Text = "elf: " + elf;
}
#endregion
#region Handle Input
/// <summary>
/// Event handler for when the Ungulate menu entry is selected.
/// </summary>
void UngulateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
currentUngulate++;
if (currentUngulate > Ungulate.Llama)
currentUngulate = 0;
SetMenuEntryText();
}
/// <summary>
/// Event handler for when the Language menu entry is selected.
/// </summary>
void LanguageMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
currentLanguage = (currentLanguage + 1) % languages.Length;
SetMenuEntryText();
}
/// <summary>
/// Event handler for when the Frobnicate menu entry is selected.
/// </summary>
void FrobnicateMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
frobnicate = !frobnicate;
SetMenuEntryText();
}
/// <summary>
/// Event handler for when the Elf menu entry is selected.
/// </summary>
void ElfMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
elf++;
SetMenuEntryText();
}
#endregion
}
}
axios/ScreenSystem/PauseMenuScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#region File Description
//-----------------------------------------------------------------------------
// PauseMenuScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using Microsoft.Xna.Framework;
#endregion
namespace GameStateManagement
{
/// <summary>
/// The pause menu comes up over the top of the game,
/// giving the player options to resume or quit.
/// </summary>
class PauseMenuScreen : MenuScreen
{
#region Initialization
/// <summary>
/// Constructor.
/// </summary>
public PauseMenuScreen()
: base("Paused")
{
// Create our menu entries.
MenuEntry resumeGameMenuEntry = new MenuEntry("Resume Game");
MenuEntry quitGameMenuEntry = new MenuEntry("Quit Game");
// Hook up menu event handlers.
resumeGameMenuEntry.Selected += OnCancel;
quitGameMenuEntry.Selected += QuitGameMenuEntrySelected;
// Add entries to the menu.
MenuEntries.Add(resumeGameMenuEntry);
MenuEntries.Add(quitGameMenuEntry);
}
#endregion
#region Handle Input
/// <summary>
/// Event handler for when the Quit Game menu entry is selected.
/// </summary>
void QuitGameMenuEntrySelected(object sender, PlayerIndexEventArgs e)
{
const string message = "Are you sure you want to quit this game?";
MessageBoxScreen confirmQuitMessageBox = new MessageBoxScreen(message);
confirmQuitMessageBox.Accepted += ConfirmQuitMessageBoxAccepted;
ScreenManager.AddScreen(confirmQuitMessageBox, ControllingPlayer);
}
/// <summary>
/// Event handler for when the user selects ok on the "are you sure
/// you want to quit" message box. This uses the loading screen to
/// transition from the game back to the main menu screen.
/// </summary>
void ConfirmQuitMessageBoxAccepted(object sender, PlayerIndexEventArgs e)
{
LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
new MainMenuScreen());
}
#endregion
}
}
axios/ScreenSystem/PhoneMainMenuScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#region File Description
//-----------------------------------------------------------------------------
// PhoneMainMenuScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
using GameStateManagement;
using Microsoft.Xna.Framework;
namespace GameStateManagement
{
class PhoneMainMenuScreen : PhoneMenuScreen
{
public PhoneMainMenuScreen()
: base("Main Menu")
{
// Create a button to start the game
Button playButton = new Button("Play");
playButton.Tapped += playButton_Tapped;
MenuButtons.Add(playButton);
// Create two buttons to toggle sound effects and music. This sample just shows one way
// of making and using these buttons; it doesn't actually have sound effects or music
BooleanButton sfxButton = new BooleanButton("Sound Effects", true);
sfxButton.Tapped += sfxButton_Tapped;
MenuButtons.Add(sfxButton);
BooleanButton musicButton = new BooleanButton("Music", true);
musicButton.Tapped += musicButton_Tapped;
MenuButtons.Add(musicButton);
}
void playButton_Tapped(object sender, EventArgs e)
{
// When the "Play" button is tapped, we load the GameplayScreen
LoadingScreen.Load(ScreenManager, true, PlayerIndex.One, new GameplayScreen());
}
void sfxButton_Tapped(object sender, EventArgs e)
{
BooleanButton button = sender as BooleanButton;
// In a real game, you'd want to store away the value of
// the button to turn off sounds here. :)
}
void musicButton_Tapped(object sender, EventArgs e)
{
BooleanButton button = sender as BooleanButton;
// In a real game, you'd want to store away the value of
// the button to turn off music here. :)
}
protected override void OnCancel()
{
ScreenManager.Game.Exit();
base.OnCancel();
}
}
}
axios/ScreenSystem/PhoneMenuScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#region File Description
//-----------------------------------------------------------------------------
// PhoneMenuScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
using System.Collections.Generic;
using GameStateManagement;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
namespace GameStateManagement
{
/// <summary>
/// Provides a basic base screen for menus on Windows Phone leveraging the Button class.
/// </summary>
class PhoneMenuScreen : GameScreen
{
List<Button> menuButtons = new List<Button>();
string menuTitle;
InputAction menuCancel;
/// <summary>
/// Gets the list of buttons, so derived classes can add or change the menu contents.
/// </summary>
protected IList<Button> MenuButtons
{
get { return menuButtons; }
}
/// <summary>
/// Creates the PhoneMenuScreen with a particular title.
/// </summary>
/// <param name="title">The title of the screen</param>
public PhoneMenuScreen(string title)
{
menuTitle = title;
TransitionOnTime = TimeSpan.FromSeconds(0.5);
TransitionOffTime = TimeSpan.FromSeconds(0.5);
// Create the menuCancel action
menuCancel = new InputAction(new Buttons[] { Buttons.Back }, null, true);
// We need tap gestures to hit the buttons
EnabledGestures = GestureType.Tap;
}
public override void Activate(bool instancePreserved)
{
// When the screen is activated, we have a valid ScreenManager so we can arrange
// our buttons on the screen
float y = 140f;
float center = ScreenManager.GraphicsDevice.Viewport.Bounds.Center.X;
for (int i = 0; i < MenuButtons.Count; i++)
{
Button b = MenuButtons[i];
b.Position = new Vector2(center - b.Size.X / 2, y);
y += b.Size.Y * 1.5f;
}
base.Activate(instancePreserved);
}
public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
{
// Update opacity of the buttons
foreach (Button b in menuButtons)
{
b.Alpha = TransitionAlpha;
}
base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
}
/// <summary>
/// An overrideable method called whenever the menuCancel action is triggered
/// </summary>
protected virtual void OnCancel() { }
public override void HandleInput(GameTime gameTime, InputState input)
{
// Test for the menuCancel action
PlayerIndex player;
if (menuCancel.Evaluate(input, ControllingPlayer, out player))
{
OnCancel();
}
// Read in our gestures
foreach (GestureSample gesture in input.Gestures)
{
// If we have a tap
if (gesture.GestureType == GestureType.Tap)
{
// Test the tap against the buttons until one of the buttons handles the tap
foreach (Button b in menuButtons)
{
if (b.HandleTap(gesture.Position))
break;
}
}
}
base.HandleInput(gameTime, input);
}
public override void Draw(GameTime gameTime)
{
GraphicsDevice graphics = ScreenManager.GraphicsDevice;
SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
SpriteFont font = ScreenManager.Font;
spriteBatch.Begin();
// Draw all of the buttons
foreach (Button b in menuButtons)
b.Draw(this);
// Make the menu slide into place during transitions, using a
// power curve to make things look more interesting (this makes
// the movement slow down as it nears the end).
float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
// Draw the menu title centered on the screen
Vector2 titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
Vector2 titleOrigin = font.MeasureString(menuTitle) / 2;
Color titleColor = new Color(192, 192, 192) * TransitionAlpha;
float titleScale = 1.25f;
titlePosition.Y -= transitionOffset * 100;
spriteBatch.DrawString(font, menuTitle, titlePosition, titleColor, 0,
titleOrigin, titleScale, SpriteEffects.None, 0);
spriteBatch.End();
base.Draw(gameTime);
}
}
}
axios/ScreenSystem/PhonePauseScreen.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#region File Description
//-----------------------------------------------------------------------------
// PhonePauseScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
using System;
namespace GameStateManagement
{
/// <summary>
/// A basic pause screen for Windows Phone
/// </summary>
class PhonePauseScreen : PhoneMenuScreen
{
public PhonePauseScreen()
: base("Paused")
{
// Create the "Resume" and "Exit" buttons for the screen
Button resumeButton = new Button("Resume");
resumeButton.Tapped += resumeButton_Tapped;
MenuButtons.Add(resumeButton);
Button exitButton = new Button("Exit");
exitButton.Tapped += exitButton_Tapped;
MenuButtons.Add(exitButton);
}
/// <summary>
/// The "Resume" button handler just calls the OnCancel method so that
/// pressing the "Resume" button is the same as pressing the hardware back button.
/// </summary>
void resumeButton_Tapped(object sender, EventArgs e)
{
OnCancel();
}
/// <summary>
/// The "Exit" button handler uses the LoadingScreen to take the user out to the main menu.
/// </summary>
void exitButton_Tapped(object sender, EventArgs e)
{
LoadingScreen.Load(ScreenManager, false, null, new BackgroundScreen(),
new PhoneMainMenuScreen());
}
protected override void OnCancel()
{
ExitScreen();
base.OnCancel();
}
}
}
axios/ScreenSystem/PlayerIndexEventArgs.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#region File Description
//-----------------------------------------------------------------------------
// PlayerIndexEventArgs.cs
//
// XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using Microsoft.Xna.Framework;
#endregion
namespace GameStateManagement
{
/// <summary>
/// Custom event argument which includes the index of the player who
/// triggered the event. This is used by the MenuEntry.Selected event.
/// </summary>
class PlayerIndexEventArgs : EventArgs
{
/// <summary>
/// Constructor.
/// </summary>
public PlayerIndexEventArgs(PlayerIndex playerIndex)
{
this.playerIndex = playerIndex;
}
/// <summary>
/// Gets the index of the player who triggered this event.
/// </summary>
public PlayerIndex PlayerIndex
{
get { return playerIndex; }
}
PlayerIndex playerIndex;
}
}
axios/ScreenSystem/ScreenManager.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
#region File Description
//-----------------------------------------------------------------------------
// ScreenManager.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Diagnostics;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using System.IO;
using System.IO.IsolatedStorage;
using System.Xml.Linq;
#endregion
namespace GameStateManagement
{
/// <summary>
/// The screen manager is a component which manages one or more GameScreen
/// instances. It maintains a stack of screens, calls their Update and Draw
/// methods at the appropriate times, and automatically routes input to the
/// topmost active screen.
/// </summary>
public class ScreenManager : DrawableGameComponent
{
#region Fields
private const string StateFilename = "ScreenManagerState.xml";
List<GameScreen> screens = new List<GameScreen>();
List<GameScreen> tempScreensList = new List<GameScreen>();
InputState input = new InputState();
SpriteBatch spriteBatch;
SpriteFont font;
Texture2D blankTexture;
bool isInitialized;
bool traceEnabled;
#endregion
#region Properties
/// <summary>
/// A default SpriteBatch shared by all the screens. This saves
/// each screen having to bother creating their own local instance.
/// </summary>
public SpriteBatch SpriteBatch
{
get { return spriteBatch; }
}
/// <summary>
/// A default font shared by all the screens. This saves
/// each screen having to bother loading their own local copy.
/// </summary>
public SpriteFont Font
{
get { return font; }
}
/// <summary>
/// If true, the manager prints out a list of all the screens
/// each time it is updated. This can be useful for making sure
/// everything is being added and removed at the right times.
/// </summary>
public bool TraceEnabled
{
get { return traceEnabled; }
set { traceEnabled = value; }
}
/// <summary>
/// Gets a blank texture that can be used by the screens.
/// </summary>
public Texture2D BlankTexture
{
get { return blankTexture; }
}
#endregion
#region Initialization
/// <summary>
/// Constructs a new screen manager component.
/// </summary>
public ScreenManager(Game game)
: base(game)
{
// we must set EnabledGestures before we can query for them, but
// we don't assume the game wants to read them.
TouchPanel.EnabledGestures = GestureType.None;
}
/// <summary>
/// Initializes the screen manager component.
/// </summary>
public override void Initialize()
{
base.Initialize();
isInitialized = true;
}
/// <summary>
/// Load your graphics content.
/// </summary>
protected override void LoadContent()
{
// Load content belonging to the screen manager.
ContentManager content = Game.Content;
spriteBatch = new SpriteBatch(GraphicsDevice);
font = content.Load<SpriteFont>("menufont");
blankTexture = content.Load<Texture2D>("blank");
// Tell each of the screens to load their content.
foreach (GameScreen screen in screens)
{
screen.Activate(false);
}
}
/// <summary>
/// Unload your graphics content.
/// </summary>
protected override void UnloadContent()
{
// Tell each of the screens to unload their content.
foreach (GameScreen screen in screens)
{
screen.Unload();
}
}
#endregion
#region Update and Draw
/// <summary>
/// Allows each screen to run logic.
/// </summary>
public override void Update(GameTime gameTime)
{
// Read the keyboard and gamepad.
input.Update();
// Make a copy of the master screen list, to avoid confusion if
// the process of updating one screen adds or removes others.
tempScreensList.Clear();
foreach (GameScreen screen in screens)
tempScreensList.Add(screen);
bool otherScreenHasFocus = !Game.IsActive;
bool coveredByOtherScreen = false;
// Loop as long as there are screens waiting to be updated.
while (tempScreensList.Count > 0)
{
// Pop the topmost screen off the waiting list.
GameScreen screen = tempScreensList[tempScreensList.Count - 1];
tempScreensList.RemoveAt(tempScreensList.Count - 1);
// Update the screen.
screen.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
if (screen.ScreenState == ScreenState.TransitionOn ||
screen.ScreenState == ScreenState.Active)
{
// If this is the first active screen we came across,
// give it a chance to handle input.
if (!otherScreenHasFocus)
{
screen.HandleInput(gameTime, input);
otherScreenHasFocus = true;
}
// If this is an active non-popup, inform any subsequent
// screens that they are covered by it.
if (!screen.IsPopup)
coveredByOtherScreen = true;
}
}
// Print debug trace?
if (traceEnabled)
TraceScreens();
}
/// <summary>
/// Prints a list of all the screens, for debugging.
/// </summary>
void TraceScreens()
{
List<string> screenNames = new List<string>();
foreach (GameScreen screen in screens)
screenNames.Add(screen.GetType().Name);
Debug.WriteLine(string.Join(", ", screenNames.ToArray()));
}
/// <summary>
/// Tells each screen to draw itself.
/// </summary>
public override void Draw(GameTime gameTime)
{
foreach (GameScreen screen in screens)
{
if (screen.ScreenState == ScreenState.Hidden)
continue;
screen.Draw(gameTime);
}
}
#endregion
#region Public Methods
/// <summary>
/// Adds a new screen to the screen manager.
/// </summary>
public void AddScreen(GameScreen screen, PlayerIndex? controllingPlayer)
{
screen.ControllingPlayer = controllingPlayer;
screen.ScreenManager = this;
screen.IsExiting = false;
// If we have a graphics device, tell the screen to load content.
if (isInitialized)
{
screen.Activate(false);
}
screens.Add(screen);
// update the TouchPanel to respond to gestures this screen is interested in
TouchPanel.EnabledGestures = screen.EnabledGestures;
}
/// <summary>
/// Removes a screen from the screen manager. You should normally
/// use GameScreen.ExitScreen instead of calling this directly, so
/// the screen can gradually transition off rather than just being
/// instantly removed.
/// </summary>
public void RemoveScreen(GameScreen screen)
{
// If we have a graphics device, tell the screen to unload content.
if (isInitialized)
{
screen.Unload();
}
screens.Remove(screen);
tempScreensList.Remove(screen);
// if there is a screen still in the manager, update TouchPanel
// to respond to gestures that screen is interested in.
if (screens.Count > 0)
{
TouchPanel.EnabledGestures = screens[screens.Count - 1].EnabledGestures;
}
}
/// <summary>
/// Expose an array holding all the screens. We return a copy rather
/// than the real master list, because screens should only ever be added
/// or removed using the AddScreen and RemoveScreen methods.
/// </summary>
public GameScreen[] GetScreens()
{
return screens.ToArray();
}
/// <summary>
/// Helper draws a translucent black fullscreen sprite, used for fading
/// screens in and out, and for darkening the background behind popups.
/// </summary>
public void FadeBackBufferToBlack(float alpha)
{
spriteBatch.Begin();
spriteBatch.Draw(blankTexture, GraphicsDevice.Viewport.Bounds, Color.Black * alpha);
spriteBatch.End();
}
/// <summary>
/// Informs the screen manager to serialize its state to disk.
/// </summary>
public void Deactivate()
{
#if !WINDOWS_PHONE
return;
#else
// Open up isolated storage
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
// Create an XML document to hold the list of screen types currently in the stack
XDocument doc = new XDocument();
XElement root = new XElement("ScreenManager");
doc.Add(root);
// Make a copy of the master screen list, to avoid confusion if
// the process of deactivating one screen adds or removes others.
tempScreensList.Clear();
foreach (GameScreen screen in screens)
tempScreensList.Add(screen);
// Iterate the screens to store in our XML file and deactivate them
foreach (GameScreen screen in tempScreensList)
{
// Only add the screen to our XML if it is serializable
if (screen.IsSerializable)
{
// We store the screen's controlling player so we can rehydrate that value
string playerValue = screen.ControllingPlayer.HasValue
? screen.ControllingPlayer.Value.ToString()
: "";
root.Add(new XElement(
"GameScreen",
new XAttribute("Type", screen.GetType().AssemblyQualifiedName),
new XAttribute("ControllingPlayer", playerValue)));
}
// Deactivate the screen regardless of whether we serialized it
screen.Deactivate();
}
// Save the document
using (IsolatedStorageFileStream stream = storage.CreateFile(StateFilename))
{
doc.Save(stream);
}
}
#endif
}
public bool Activate(bool instancePreserved)
{
#if !WINDOWS_PHONE
return false;
#else
// If the game instance was preserved, the game wasn't dehydrated so our screens still exist.
// We just need to activate them and we're ready to go.
if (instancePreserved)
{
// Make a copy of the master screen list, to avoid confusion if
// the process of activating one screen adds or removes others.
tempScreensList.Clear();
foreach (GameScreen screen in screens)
tempScreensList.Add(screen);
foreach (GameScreen screen in tempScreensList)
screen.Activate(true);
}
// Otherwise we need to refer to our saved file and reconstruct the screens that were present
// when the game was deactivated.
else
{
// Try to get the screen factory from the services, which is required to recreate the screens
IScreenFactory screenFactory = Game.Services.GetService(typeof(IScreenFactory)) as IScreenFactory;
if (screenFactory == null)
{
throw new InvalidOperationException(
"Game.Services must contain an IScreenFactory in order to activate the ScreenManager.");
}
// Open up isolated storage
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
// Check for the file; if it doesn't exist we can't restore state
if (!storage.FileExists(StateFilename))
return false;
// Read the state file so we can build up our screens
using (IsolatedStorageFileStream stream = storage.OpenFile(StateFilename, FileMode.Open))
{
XDocument doc = XDocument.Load(stream);
// Iterate the document to recreate the screen stack
foreach (XElement screenElem in doc.Root.Elements("GameScreen"))
{
// Use the factory to create the screen
Type screenType = Type.GetType(screenElem.Attribute("Type").Value);
GameScreen screen = screenFactory.CreateScreen(screenType);
// Rehydrate the controlling player for the screen
PlayerIndex? controllingPlayer = screenElem.Attribute("ControllingPlayer").Value != ""
? (PlayerIndex)Enum.Parse(typeof(PlayerIndex), screenElem.Attribute("ControllingPlayer").Value, true)
: (PlayerIndex?)null;
screen.ControllingPlayer = controllingPlayer;
// Add the screen to the screens list and activate the screen
screen.ScreenManager = this;
screens.Add(screen);
screen.Activate(false);
// update the TouchPanel to respond to gestures this screen is interested in
TouchPanel.EnabledGestures = screen.EnabledGestures;
}
}
}
}
return true;
#endif
}
#endregion
}
}

Archive Download the corresponding diff file

Branches

Number of commits:
Page rendered in 0.22680s using 13 queries.