El tiempo de juego en Silverlight 5

Algo que hechamos en falta en la nueva actualización de Silverlight 5 es la clase equivalente a Game de XNA. ¿Cual es el equivalente en Silverlight?

Después de instalar el Silverlight Toolkit, creamos un nuevo proyecto usando la plantilla Silverlight 3D. Abrimos MainPage.xaml y vemós la declaración del objeto DrawingSurface y cómo está trucado el evento Draw. Ahora vamso a ver MainPage.xaml.cs y vemos la implementación del evento myDrawingsurface_Draw. Después de llamar a scene.Draw(), se llama a e.InvalidateSurface(), que le dice a Silverlight que este objeto debe ser repintado. Normalmente Silverlight pinta el el objeto una vez al inicio, y sólo se repinta cuando algo ha cambiado (quizás porque se ha redimensionado, o porque se ha movido algo). Pero cuando el manejador invalida la superficie, hace que se vuelva a pintar, lo que la invalida de nuevo, y hace que se vuelva a pintar, y así sucesivamente. Esto crea un bucle infinito, con la superficie que se pinta contínuamente, justo lo que queremos para un bucle de juego.

Fijáos que el método UserControl_Loaded en MainPage.xaml.cs, está enlazado al evento UserControl.Loaded. Esto es el equivalente a los métodos Initialize y LoadContent de XNA.

Bueno vale, ¿pero cómo montamos un juego encima de esto?. Mirad el juego XNA Platformer en c:/Program Files (x86)/Microsoft SDKs/Silverlight/v5.0/Toolkit/Sep11/Source/Sample source code.zip/Xna). Vamos a ver el método myDrawingSurface_Draw de MainPage.xaml.cs. Es muy sencillo:

private void myDrawingSurface_Draw(object sender, DrawEventArgs e)
{
platformerGame.Update(e);
platformerGame.Draw(e);

e.InvalidateSurface();
}

Aquí tenemos el bucle de juego. Gracias a la llamada InvalidateSurface, se llama al update y al draw lo más rápido posible.

Si preferís usar un sistema con tiempo, podéis hacer lo siguiente:

readonly TimeSpan TargetElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 60);
readonly TimeSpan MaxElapsedTime = TimeSpan.FromTicks(TimeSpan.TicksPerSecond / 10);

TimeSpan accumulatedTime;

private void myDrawingSurface_Draw(object sender, DrawEventArgs e)
{
TimeSpan elapsedTime = e.DeltaTime;

if (elapsedTime > MaxElapsedTime)
{
elapsedTime = MaxElapsedTime;
}

accumulatedTime += elapsedTime;

while (accumulatedTime >= TargetElapsedTime)
{
Update();
accumulatedTime -= TargetElapsedTime;
}

Draw();
e.InvalidateSurface();
}

Espero que os guste.

Juan María Laó Ramos.

Artículo original.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *