Jesper Niedermann's .NET Blog
about .NET and related technologies RSS 2.0
# Tuesday, 26 July 2011

I and a team of 1 graphic artist and 1 sound engineer just finished our first game for Windows Phone 7 called “Photo Challenge” a few weeks ago. We planned this pretty simple game to get experience before going for the big hit. The concept has been seen before. A Puzzle Slider where you have to solve a square puzzle with 2x2, 3x3, 4x4, 5x5 or 6x6 squares with one square missing. The Puzzle can be made from you own photos or from some build in ones. Here is a few screenshots:

screenshot_1screenshot_2screenshot_4screenshot_7

The point of the game is to solve the puzzle as fast as possible to make it to the leaderboards. We used the great service Mogade.com for the leaderboards. I plan to cover that aspect in another post.

We are very satisfied with the style and feel of the final game. Even for such a simple game details are important. Similar competing games seems to have been made in Silverlight and thus are more limited with regards to graphics and sound than our XNA game.

Some of the learnings from making the game are:

  • XNA is a fantastic framework and my own framework for XNA developed over time for PC and XBox could be used directly with very few changes.
  • WP7 has a fantastic developer platform. IMO better than the iPhones.
  • The WP7 API’s still lacks a lot of functionality that is present in the iPhone API’s but slowly catching up.
  • If you use some of the build in “Tasks” like the PhotoChooserTask or the MarketplaceReviewTask you cannot play sounds on the device if it is connected via USB to the computer. Sounds like a small thing but it means you cannot debug on the device ! Really horrible. My solution was to not play music and sound effects in the DEBUG edition.
  • On the other hand you can debug on the emulator. On the iPhone it is extremly important to debug directly on the iPhone because the iPhone simulator cannot be trusted. I have often experienced that code working in the iPhone simulator was not working on the device. This never happened once for the WP7 emulator and my Samsung Omnia 7. Still it is important to be able to debug on the device since there are things not available in the emulator.
  • As mentioned the API is somewhat lacking. E.g it is impossible to send images in emails via the EmailComposeTask. It is not possible to integrate facebook in an XNA app and so forth. The last one is supposed to be fixed in the Mango update since it has opened up for mixing Silverlight and XNA. I have not tried it yet. But hope it will be possible. Facebook integration in games is almost a must these days.
  • Despite being extremely happy with the developing experience for WP7 the iPhone is still an overall better smartphone experience in my opinion (seen from a user perspective). I hope and think WP7 will catch up in time. Competition is good.
Tuesday, 26 July 2011 23:47:58 (GMT Daylight Time, UTC+01:00)  #    Comments [5] -
Games & Puzzles | Windows Phone 7 | XNA
# Wednesday, 12 May 2010

Windows developers who are used to click events in WinForms, WPF or Silverlight might miss click and double click events, but because of the game loop where everything is drawn and updated every few milliseconds an event based approach is probably not a good idea in most cases. Not so much because of the performance of an event based approach, but more because the complexity is overwhelming. If several users clicks and double clicks several keys on the keyboard simultaneously, how would you decide which of these are clicked and in which order, and further more it is not obvious to subscribers of the events that they are in the game loop, so they might do code which performs inadequately.

I have made a few generic classes that expands the MouseState, GamePadState and KeyboardState in order to make click “events” available. But of course I utilize the standard polling mechanism in XNA which is to call GetState() on each device.

The approach is that I call my own version of GetState() in the main game loop. My GetState() method first enqueues the state in a Queue, and then dequeues all states older than 500 ms, before the state is returned. In this way a historical map of user interactions is maintained at all times.

Now I can simply check if a key or button was clicked by checking if the key was pressed and then released “historically”. Similarly I can check for double click by checking if the key or button was pressed, then released, then pressed again and then released again.

Now you probably realize why I go back 500 ms. It is because this is the standard time in which a double click should be executed.

I have used this approach in the game Protect the Carrot at http://ptc.codeplex.com and it works like a charm (The url for the game does not work today, since the game will only be published in a few weeks).

Here is the implementation of the MouseExtended class which uses this approach:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework;

namespace PTC.Input
{
public class MouseExtended : InputDeviceExtended<MouseState>
{
private static MouseExtended m_Current;
public static MouseExtended Current
{
get
{
if (m_Current == null)
{
m_Current = new MouseExtended();
}
return m_Current;
}
}

public MouseState GetState(GameTime currentTime)
{
DequeueOldStates(currentTime);
MouseState state = Mouse.GetState();
EnqueueNewState(currentTime, state);
return state;
}

private bool ClickCount(MouseButton checkButton, int requiredCount)
{
ButtonState found = ButtonState.Released;
int count = 0;
foreach (InputStateExtended<MouseState> stateExt in RecordedStates)
{
if (found == ButtonState.Pressed &&
ButtonStateToCheck(stateExt.State, checkButton) == ButtonState.Released)
{
count++;
if (count >= requiredCount)
return true;
}
found = ButtonStateToCheck(stateExt.State, checkButton);
}
return false;
}

private ButtonState ButtonStateToCheck(MouseState state, MouseButton checkButton)
{
switch (checkButton)
{
case MouseButton.Left:
return state.LeftButton;
case MouseButton.Middle:
return state.MiddleButton;
case MouseButton.Right:
return state.RightButton;
case MouseButton.XButton1:
return state.XButton1;
case MouseButton.XButton2:
return state.XButton2;
default:
return state.LeftButton;
}
}

public bool WasSingleClick(MouseButton checkButton)
{
return(ClickCount(checkButton, 1));
}

public bool WasDoubleClick(MouseButton checkButton)
{
return (ClickCount(checkButton, 2));
}

}
}

And here is the generic InputDeviceExtended class which MouseExtended inherits:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace PTC.Input
{
public class InputDeviceExtended<S> where S : struct
{
private Queue<InputStateExtended<S>> m_RecordedStates = new Queue<InputStateExtended<S>>();

public Queue<InputStateExtended<S>> RecordedStates
{
get { return m_RecordedStates; }
}

private Stack<InputStateExtended<S>> m_StatesForReuse = new Stack<InputStateExtended<S>>();

protected void EnqueueNewState(GameTime time, S state)
{
if (!state.Equals(m_CurrentState))
{
m_CurrentState = state;
m_RecordedStates.Enqueue(CreateState(time, state));
}
}

private S m_CurrentState;
public S CurrentState
{
get { return m_CurrentState; }
}

protected void DequeueOldStates(GameTime currentTime)
{
InputStateExtended<S> state = null;
if (m_RecordedStates.Count > 0)
{
state = m_RecordedStates.Peek();
}
if (state != null && state.StateTime < currentTime.TotalRealTime.Subtract(new TimeSpan(0, 0, 0, 0, InputDeviceConstants.ClickCountTimeMS)))
{
m_StatesForReuse.Push(m_RecordedStates.Dequeue());
DequeueOldStates(currentTime);
}
}

private InputStateExtended<S> CreateState(GameTime time, S state)
{
if (m_StatesForReuse.Count > 0)
{
//Reuses the object to fight of the GC
InputStateExtended<S> stateExt = m_StatesForReuse.Pop();
stateExt.StateTime = time.TotalRealTime;
stateExt.State = state;
return stateExt;
}
else
{
return new InputStateExtended<S>(time, state);
}
}
}
}

Notice that the Recorded States are reused. When dequeued from the queue the are added to a reuse stack. This is a standard trick to fight of the Garbage Collector, by always keeping a reference to objects on the heap they never become garbage + they are reused so the memory use will not explode.

I have also implemented the necessary extended classes for the Keyboard and the gamepad. I have included them in the attachment to this post. I have not tested the GamepadExtended class since I do not own a Gamepad, but it is implemented exactly as the keyboard and mouse classes and ought to work.

To wire up the new classes you just add the relevant Getstate() calls to the Update game loop like so:

protected override void Update(GameTime gameTime)
{
KeyboardExtended.Current.GetState(gameTime);
MouseExtended.Current.GetState(gameTime);
base.Update(gameTime);
}

And then you can check for click and double click “events”. For instance you check for double click of the left mouse button like this:

if(MouseExtended.Current.WasDoubleClick(MouseButton.Left)))
{
//Do double click reaction
}

Hope you like the stuff.And look out for the amazing “Protect The Carrot” game within the next month or so, at http://ptc.codeplex.com

In InputDeviceExtended.zip I have included the code for all the InputDevice classes.

Wednesday, 12 May 2010 21:38:51 (GMT Daylight Time, UTC+01:00)  #    Comments [0] -
.NET | Tips & Tricks | XNA
# Friday, 13 November 2009

I am currently developing the game Klimakonflikt with 5 other guys. It is a Retro arcade game, Pac-man style, with nice 2D Graphics and music. Here is a screenshot from the game:

klimakonflikt_screenshot

The current release, documentation and source code can be downloaded from here http://klimakonflikt.codeplex.com 

The game is inherently for 2 players but we are working on the single player edition. The AI in the current release is pretty daft, but in the next release it will be much improved. Also we are working on a WPF leveleditor, powerups and other fun stuff.

One of my co-developers Jakob has released a blog about the game and XNA development in general at http://xnafan.net

Friday, 13 November 2009 23:11:29 (GMT Standard Time, UTC+00:00)  #    Comments [0] -
.NET | Games & Puzzles | WPF | XNA
Archive
<2017 October>
SunMonTueWedThuFriSat
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234
About the author/Disclaimer
I am a software architect with focus on Microsoft Technologies. I have been working with these in different large companies since 1995. I am currently employed at UVdata A/S.
Here is my View Jesper Niedermann's profile on LinkedIn

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

Privacy policy
The privacy policy of this site.

© Copyright 2017
Jesper Niedermann
Sign In
Statistics
Total Posts: 28
This Year: 0
This Month: 0
This Week: 0
Comments: 32
All Content © 2017, Jesper Niedermann
DasBlog theme 'Niedermann' created by Jesper Niedermann, based on 'Business' created by Christoph De Baene (delarou)