Friday, August 21, 2009

Cybraphon



A friend I used to work with back in my Edinburgh days has been working on some pretty fantastic stuff recently. He and his collaborators have been using computer-orchestrated electronic actuators to control a variety of physical music-producing devices.

Their latest creation (shown in the video above) is Cybraphon, a one-"man" wardrobe band.

I really like it.

Wednesday, August 19, 2009

SubMariner



I really should be working on Saucer Pilots, but as I've said before, I'm much better at starting projects than finishing them...

Thursday, August 13, 2009

XNA Force Feedback Helper Class

This is a little helper class I whipped up to manage force feedback vibrations in XNA. The XNA libraries themselves just have a method you call to set the instantaneous left/right vibration force. In games, however, you generally want the feedback to last over a period of time, and you may have more than one force feedback event happening at the same time.

This code provides a "fire-and-forget" interface for triggering vibrations. Add a call to update the ForceFeedbackManager in your game's update code. Call AddVibration whenever you want to trigger force feedback.

Note: this code is not threadsafe - you must be triggering feedback from the same thread you call Update from.


public class Vibration
{
float leftMotor;
float rightMotor;
float msLeft;

public float LeftMotor
{
get { return leftMotor; }
set { leftMotor = value; }
}

public float RightMotor
{
get { return rightMotor; }
set { rightMotor = value; }
}

public float MSLeft
{
get { return msLeft; }
set { msLeft = value; }
}

public Vibration(float leftMotor, float rightMotor, float durationMS)
{
this.leftMotor = leftMotor;
this.rightMotor = rightMotor;
this.msLeft = durationMS;
}
}

public class ForceFeedbackManager
{
private PlayerIndex playerIndex;
List<Vibration> vibrations = new List<Vibration>();

public ForceFeedbackManager(PlayerIndex playerIndex)
{
this.playerIndex = playerIndex;
}

public void AddVibration(float leftMotor, float rightMotor, float durationMS)
{
vibrations.Add(new Vibration(leftMotor, rightMotor, durationMS));
}

public void Update(float msElapsed)
{
List<Vibration> toDelete = new List<Vibration>();

foreach (Vibration vibration in vibrations)
{
vibration.MSLeft -= msElapsed;

if (vibration.MSLeft < 0.0f)
{
toDelete.Add(vibration);
}
}

foreach (Vibration vibration in toDelete)
{
vibrations.Remove(vibration);
}

float leftMotor;
float rightMotor;

GetVibration(out leftMotor, out rightMotor);

GamePad.SetVibration(playerIndex, leftMotor, rightMotor);
}

public void GetVibration(out float leftMotor, out float rightMotor)
{
leftMotor = 0.0f;
rightMotor = 0.0f;

foreach (Vibration vibration in vibrations)
{
leftMotor = Math.Max(leftMotor, vibration.LeftMotor);
rightMotor = Math.Max(rightMotor, vibration.RightMotor);
}
}
}

Tuesday, August 11, 2009

sfxr - A Great Free Sound Effect Generator



One of the problems I always have when I'm working on a game project is sourcing sound effects. Recently, I came across sfxr, a very nice program for creating sound effects. It was a great help when I was working on Saucer Pilots.

It is basically a little software synth with a bunch of variables you can tweak to generate a wide variety of sounds. A helpful set of presets are provided for generating commonly needed classes of video game sounds.

Once you find something you like, export it to a WAV file and you are good to go. Very handy little utility.

Thursday, August 6, 2009

Saucer Pilots - XNA Dream Build Play 2009



Whew! I just squeaked an entry in under tonight's deadline for the 2009 XNA Dream Build Play competition.

Last Monday, I was messing around with a new "flying saucer" game prototype idea. It seemed like it had promise, so I kicked into high gear to try to get something submittable for the competition. I initially got the submission date wrong, and thought I had until this Sunday. A few days ago, I realized my error and really had to step things up.

The competition was a good impetus to get me to actually finish something. I'm generally much more fond of starting things than completing them...

Anyway, the game is "Saucer Pilots" - a 1-4 player saucer flying game with five different gameplay modes. Xbox LIVE avatars are used for saucer pilot models (avatars do not appear in this video, as they are not visible on the PC). The physics implementation I'm using is Farseer.

Overall, I think it turned out pretty well for a week-and-a-half effort. The only thing that made that timeline possible was the framework on top of XNA that I've developed over the past year. And help from Sherry.

Oh, and did I mention that it has fishing?

Tuesday, March 24, 2009

Creating Playlists With Linq - Another Great Use For CodeDomProvider



I recently found a new use for dynamically-compiled assemblies using CodeDomProvider. Combined with Linq, it enables the ultimate flexibility in music playlist generation.

My "Code Playlists", are snippets of code that can do whatever they want as long as they return an enumerable collection of song objects. As you can see above, simple Linq expressions make it really easy to generate pretty much any collection of songs that my music metadata can support.

Thursday, March 12, 2009

WPF Progress Bars Revisited

Because some people were having trouble understanding how to use my original WPF progress bar code, I thought I'd post an updated, easier to use version.

The problems people were having pretty much all centered around not understanding how to run their code in a background thread. My updated version handles this for you.

First, please have a look at the original post, as you will need some of the code from there:

WPF Progress Bars

The XAML and IProgressContext code is still the same, but here is an updated partial class for the progress dialog, along with a delegate definition that it requires:

public delegate void ProgressWorkerDelegate(IProgressContext progressContext);

public partial class ProgressDialog : Window, IProgressContext
{
private bool canceled = false;
private ProgressWorkerDelegate workDelegate = null;

public bool Canceled
{
get { return canceled; }
}

public ProgressDialog() : this(null)
{            
}

public ProgressDialog(ProgressWorkerDelegate workDelegate)
: this(workDelegate, false)
{
}

public ProgressDialog(ProgressWorkerDelegate workDelegate, bool startInBackground)
{
this.workDelegate = workDelegate;

InitializeComponent();

CancelButton.Click += new RoutedEventHandler(CancelButton_Click);

if (workDelegate != null)
{
if (startInBackground)
{
new Thread(new ThreadStart(StartWork)).Start();
}
else
{
StartWork();
}
}
}

private void StartWork()
{
workDelegate(this);
}

void CancelButton_Click(object sender, RoutedEventArgs e)
{
canceled = true;
CancelButton.IsEnabled = false;
}

public void UpdateProgress(double progress)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Progress.SetValue(ProgressBar.ValueProperty, progress); }, null);
}

public void UpdateStatus(string status)
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { StatusText.SetValue(TextBlock.TextProperty, status); }, null);
}

public void Finish()
{
Dispatcher.BeginInvoke(DispatcherPriority.Background,
(SendOrPostCallback)delegate { Close(); }, null);
}
}


The key difference is that you can now pass the dialog a delegate that will be used to do your work, and can have it automatically get run in the background.

To use it, do something like this:

ProgressDialog progressDialog = new ProgressDialog(MyWorkFunction, true);
progressDialog.ShowDialog();


Note that I am using ShowDialog() above to keep the operation modal. If you want the rest of your UI to still accept input, use Show() instead.

Your function to actually do the work would look something like this:

void MyWorkFunction(IProgressContext progressContext)
{
for (int i = 0; i < 100; i++)
{
if (myProgressContext.Canceled)
break;

progressContext.UpdateProgress((double)i / 100.0);
progressContext.UpdateStatus("Doing Step " + i);
}

progressContext.Finish();
}