I am very proud to announce the public beta of Xnaml, a Silverlight plugin for Xna on WIndows Phone 7, Xbox 360 and Pc. Making user interface with Xna it a too long and boring task. I’ve made a plugin that load Xaml page and c# sub code to reproduce the main feature of the Silverlight technology :
- Dependency Properties
- Inheritance DP (FontProperty, ForegroundProperty, DataContext, …)
- Storyboards
- Binding
- Xaml parseur
- Resources
- Render Transform
- Easing animation
- Generics/Theme.xaml files
- Style
- Template
- VisualStateManager
- and so on …
And main known controls :
- Border
- Button
- ContentControl
- Grid
- Image
- ItemsControl
- ItemsPresenter,
- ControlPresenter
- RootElement (similar to Window)
- ScrollViewer
- ScrollContentPresenter
- StackPanel
- TextBlock
- Canvas
- TextBox
- Panel
- Page
- …
And specifc controls :
- Iphone Scoller
- Panaorama
- WP7 Date picker
- …
I respect all the WPF hierarchy : DispatcherObject-> DependencyObject-> Visual -> UIElement -> FrameworkElement/FrameworkContent
Just Xna !
My engine is designed to run in a pure Xna environement on all supported device. My engine is extensible, you can add your own controls, inherit from base classes (such as Control or Pane) to make your own behavior. The compatibility with Xaml is complete. Create your interface on Blend and make a simple copy/past action to add the Xaml file in your Xna project ! Extract a C# code from a Silverlight project and just add it to your own Xna project !
Getting started
The Xnaml Plugin is based on two Assemblies :
- Arcane.Xna.Windows with contains the main Silverlight classes adapted to Xna
- Arcane.Xna.Windows.Controls witch contains the main controls (Button, PanoramaControl, etc.)
Reference this two Dlls in you Xna project :
Add a using reference in your game class like this :
using Arcane.Xna.Windows;
Then create a new Arcane.Xna.Windows.XnamlGameComponent object and add it to the component list of your game class :
XnamlGameComponent component = new XnamlGameComponent(this);
this.Components.Add(component);
The Silverlight plugin is now ready ! And the Application.Current object is instanced and ready to use. We just have to fill its RootVisual property.
Lets try to add a first user interface. We will make the Application bar of the Windows Phone as a sample :
The first hing to do is to create the fonts we need here. Add to sprite font to the content project. The first will be called NormapSpriteFont and will create a sprteshhet for a Segoe UI with a size of 20. The second will be named SmallSpriteFont and will have the same font family with with a font size of 10.
Add a reference to the font identifier to the Application object to
define the default font to use in TextBlock and ContentPresenter : For that, just add after the last instruction this line :
Application.Current.DefaultFontAssetName = “NormalSpriteFont”;
Now create a sub directory to your project named Presentations. We will add in this folder all your xaml file and associed c# file. Right click on this directory and add a new Xml file named MainPage.xnaml :
Add this content :
<?xml version=”1.0″ encoding=”utf-8″ ?>
<Page
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
x:Name=”Page”
xmlns:phone=”clr-namespace:Arcane.TowerDefense.Controls.Phone;assembly=Arcane.TowerDefense”
xmlns:interface=”clr-namespace:Arcane.TowerDefense.Controls.Interface;assembly=Arcane.TowerDefense”
WindowTitle=”Page”
FlowDirection=”LeftToRight”>
<Grid x:Name=”LayoutRoot”>
</Grid>
</Page>
That an easy to undertand Xaml code. The Page is a container control to host your interface. It can contain only one control. Here this orphan control is a grid, named LayoutRoot. Save this file and change its compilation mode to EmbeddedResource.
Now add a C# classic file named MainPage.xnaml.cs. Add the same using instruction to this file and change the code to :
public class MainPage : Page
{
public MainPage()
{
Application.LoadComponent(this, new System.Uri(“/XnamlWindowsPhoneGame;component/Presentations/MainPage.xnaml”, System.UriKind.Relative));
}
}
Now the C# and xnaml file are linked. Add this instruction in the Initialize game method :
protected override void Initialize()
{
// TODO: Add your initialization logic here
Application.Current.RootVisual = new Presentations.MainPage();
base.Initialize();
}
And run the application. You will see nothing else than the cornflower blue screen. Lets add some color.
Change the MainPage.xnaml content to add a Background to the LayoutRoot grid :
<Grid x:Name=”LayoutRoot” Background=”#FFFF0000″>
</Grid>
Relaunch the application, now the screen is red :
Add Some margin to the grid to see once again le back blue screen :
<Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>
</Grid>
Now add some children. Lets try a Canvas, StackPanel and Grid childrens :
<Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>
<Canvas Margin=”-10″ Background=”#CCFFFFFF”></Canvas>
<StackPanel Width=”50″ Height=”30″ Background=”Yellow”></StackPanel>
<Grid Margin=”20″ Background=”#CCCCCC”></Grid>
</Grid>
If you launch the application now, you get a dirty screen like this :
That’s normal : all children are layout uppon each others. Add some columns and row to layout this :
<Grid x:Name=”LayoutRoot” Background=”#FFFF0000″ Margin=”10″>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Canvas Margin=”-10″ Background=”#CCFFFFFF”></Canvas>
<StackPanel Grid.Row=”0″ Grid.Column=”1″ Width=”50″ Height=”30″ Background=”Yellow”></StackPanel>
<Grid Grid.Row=”1″ Margin=”20″ Background=”#CCCCCC”></Grid>
</Grid>
Relaunch the application you will have this :
Now lets try to add some texte and some pictures to this interface. I downloaded from web some picture like this :
to add to my interface. I put this icons in a folder named Icons in the content project :
Now lets begin to create an application bar.
Change the layoutroot Grid for this :
<Grid Name=”LayoutRoot”>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width=”Auto”></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid x:Name=”WorldZone” Background=”Transparent”>
</Grid>
<Grid x:Name=”MenuGrid” Grid.Column=”1″ Width=”72″ Background=”#1F1F1F”>
<Grid x:Name=”ThreePointButton”
HorizontalAlignment=”Left” VerticalAlignment=”Top”
Background=”Transparent” Margin=”0,10″
Width=”72″ Height=”36″>
<Image Source=”Icons/ThreePoints” Width=”32″ Height=”16″ Margin=”20,5″/>
</Grid>
<StackPanel x:Name=”CliffButtons” Orientation=”Vertical” HorizontalAlignment=”Left” VerticalAlignment=”Center”>
<Grid x:Name=”RiseButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto”></ColumnDefinition>
<ColumnDefinition Width=”12″></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source=”Icons/calend” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
<TextBlock Text=”Calendar” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
</Grid>
<Grid x:Name=”SunkButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto”></ColumnDefinition>
<ColumnDefinition Width=”12″></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source=”Icons/compas” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
<TextBlock Text=”Compas” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
</Grid>
<Grid x:Name=”LevelingButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto”></ColumnDefinition>
<ColumnDefinition Width=”12″></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source=”Icons/info” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″ RenderTransformOrigin=”0.5,0.5″>
<Image.RenderTransform>
<ScaleTransform ScaleX=”0.5″ ScaleY=”0.8″></ScaleTransform>
</Image.RenderTransform>
</Image>
<TextBlock Text=”In your face” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
</Grid>
<Grid x:Name=”RampButton” Margin=”11,5″ HorizontalAlignment=”Left” Background=”Transparent”>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”Auto”></ColumnDefinition>
<ColumnDefinition Width=”12″></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Image Source=”Icons/info” VerticalAlignment=”Top” Width=”49″ Height=”50″ Margin=”0,5″/>
<TextBlock Text=”info” Foreground=”White” Grid.Column=”2″ FontFamily=”SmallSpriteFont”></TextBlock>
</Grid>
</StackPanel>
<StackPanel Orientation=”Vertical” Margin=”200,20″ HorizontalAlignment=”Left” VerticalAlignment=”Top”>
<TextBlock Text=”Menu item 1″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
<TextBlock Text=”Menu item 2″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
<TextBlock Text=”Menu item 3″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
<TextBlock Text=”Menu item 4″ Foreground=”White” HorizontalAlignment=”Left” Margin=”0,25″></TextBlock>
</StackPanel>
</Grid>
</Grid>
Wow that’s bigger 🙂 The LayoutRoot have to column, the first take all the place it can, the second take only the place asked by its children. The second children is the Application bar, it takes 72 pixel like the UI specification said. At the top with an VerticalAlignment tp top i put 3 points to expand, collapse the application bar. I use a StackPanel to layout my icons. And icon is an image and a small text at the left that is not visible in the collapsed state.Just for the fun you will notice that i put to the last icon a rendertransform to scale the Image. To finish, i put another StackPanel with menu items. If you launch it you will see this :
Are we on Silverlight or Xna here oO ? 🙂 Yes that’s pure Xna !
Lets try to add the expanded state and use some storyboards. Open the MainPage.xnaml.cs file we’ve created before. Override the OnApplyTemplate and try to thet the UIElements named “ThreePointButton” and “MenuGrid” in the xnaml file :
public Grid MenuGrid
{
get;
set;
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
MenuGrid = this.GetTemplateChild(“MenuGrid”) as Grid;
Grid grid = this.GetTemplateChild(“ThreePointButton”) as Grid;
if (grid != null)
grid.Tap += new RoutedEventHandler(grid_Tap);
}
void grid_Tap(object sender, RoutedEventArgs e)
{
}
We try to get the Grid and if it suceed we connect to the Tap event. Be sure to intercept tap event that your grid have a visible background (with an Alpha different of 0). Add a boolean to the MainScreenc lass named expanded. It will inform us if the application bar is expanded or not.
bool isExpanded;
Add this utility function to the end of the MainScreen class :
public DoubleAnimation CreateAnimation(DependencyObject obj, DependencyProperty prop, double fromValue, double toValue, double milliseconds, EasingMode easing)
{
CubicEase ease = new CubicEase() { EasingMode = easing };
DoubleAnimation animation = new DoubleAnimation
{
Duration = new Duration(TimeSpan.FromMilliseconds(milliseconds)),
From = fromValue,
To = Convert.ToDouble(toValue),
FillBehavior = FillBehavior.HoldEnd,
EasingFunction = ease
};
Storyboard.SetTarget(animation, obj);
Storyboard.SetTargetProperty(animation, new PropertyPath(prop));
return animation;
}
I use this function inside my Silverlight project we no changes !
It create a DoubleAnimation on the specified object/property from the specified value to the specified value.
To correct errors add two more using :
using Arcane.Xna.Windows.Media;
using Arcane.Xna.Windows.Data;
Now fill the tap event method :
void grid_Tap(object sender, RoutedEventArgs e)
{
e.Handled = true;
Storyboard storyboard = new Storyboard();
if (isExpanded)
{
storyboard.Children.Add(CreateAnimation(MenuGrid, FrameworkElement.WidthProperty, 500, 72, 200, EasingMode.EaseOut));
}
else
{
storyboard.Children.Add(CreateAnimation(MenuGrid, FrameworkElement.WidthProperty, 72, 500, 200, EasingMode.EaseOut));
}
storyboard.Begin();
isExpanded = !isExpanded;
}
We ask the engine that the event is handled. We change the expanded state and launch a new storyboard. Launch the application, you will have this :
[View:http://www.youtube.com/watch?v=nDP_iAAL9JQ:550:0]
As you can see, the Xnaml component is very simple and 100% compatible with Silvelright/WPF. In some case we can have better performance in Xna for UI than Silverlight with its compositor thread. We will see in next tutorial how to use template/style.
You can look at this video to see a sample of me that recreate the panorama control very easely by a simple copy past from an old codeproject about panorama and pivot control.
[View:http://www.youtube.com/watch?v=VgI9SCbURU4:550:0]
[soon]
Valentin
Ca a l’air intéressant 🙂 Par contre, j’ai raté le lien de téléchargement ?
A bientôt
Chris
Great job! Please let us know when you got a version ready for public testing 😉
I wondered how different you are from RedBadger’s XPF? Could you post a quick blog entry about it?
Seem quite good, but where is the download link ?
I want some beta testers before release the link 🙂
The different with XPF ? i full compatible with Silverlight 🙂 I have more controls and functionnalities
Hi!
I was working on something much more simpler http://silvermenu.codeplex.com than what you have here. I guess your plugin renders mine useless 😛
I’d like to give it a try and test it if you don’t mind.
Thank you for your awesome work!
Hey Valentin! Congrats for this nice framework!
Si tu veux, je peux tester ta version beta! Tu peux me contacter par Twitter (@robertos_br) ou par mail (robertos (at) virtualdreams (point) com (point) br).
A+!
All I can say is wow – sweet.
Hi,
Good work. I’d be happy to beta test this for you. @SteveDunn
How is this project is coming? I am sorta curious
When will this be released to the public? It looks great!
Projet fort intéressant et qui permet de créer des interfaces relativement “simplement” pour le peu que l’on connaisse WPF ou Silverlight…
Parce que ce taper tout du code pour faire une interface sous XNA c’est un peu génant; ils auraient pu prévoir le GUI dans le framework…
Mais bon là nous aurons une solution de rechange plus que viable…
Par contre, avez-vous réécrits toutes les classes du framework Silverlight pour être utilisable sous XNA ? Parce que je n’ai lu nul part que Silverlight pouvait tourner sous X360, et comme vous dites que XnamlComponent tourne sous X360, j’ai comme un doute…
Par contre pour être bêta testeur, où faut-il signer ?
If this is a “public beta,” where’s the download?
Any updates on this? Is it available to try/test?
Excelent work, i confess that i can´t think in a more flexible way of make GUI , i would like to be a beta tester of your work
Any idea when your thinking of releasing something for the world to see?
Quand est ce que’il sera disponible pour telechargement .
Merci,
Alex
Was this project ever released? Is there a download link?
Thanks,
-Andy
Absolument incroyable, c’est vraiment très fort, et c’est tout à fait ce que beaucoup de monde doit rechercher : la simplicité de création d’interface de Silverlight allié à l’incroyable puissance de XNA !
Si jamais tu as monté / monte une entreprise dans le développement de jeux XNA pour windows phone, et que par hasard tu commence à recruter des Concepteurs de jeu / des développeurs, n’hésites pas à nous transmettre des coordonnées pour que l’on puisse te joindre !
Vivement que tout ça soit partagé !!
Amazing Job!!! Can I be beta-test of your product?
Thanks and Regards!
roelarmas@gmail.com