 |
|
 |
|
|
Physics Behaviors for Silverlight 3! |
|
Andy's Blog
|
By Andy Beaulieu on
7/15/2009 7:21 PM
|
|
|
|
Today I released an initial version of “Physics Helper 3” to Codeplex. This includes a collection of new Behaviors for Expression Blend which makes it very quick to create physics games and simulations in Silverlight using the Farseer Physics Engine. This release requires Silverlight 3 and Expression Blend 3, which you can get here.
DOWNLOAD PHYSICS HELPER 3
Demos
There are four new demos using Behaviors, plus the original demos depending on the older User Control model. Note that version 3 still supports the User Control model, but I would recommend checking out the new Behaviors model as there is nice design time support in Blend.
VIEW ALL DEMOS
|
| Falling Astronaut | |
|
| Rag Doll | |
|
| Truck w/Camera | |
|
| Flying Astronaut | |
Getting Started Videos
I have a couple of quick (10 min) screen casts which show how to use the new Physics Behaviors:
VIDEO ON "THE BASICS": VIEW | DOWNLOAD
VIDEO ON "JOINTS + PROGRAMMING": VIEW | DOWNLOAD
Enhancing Behaviors with Code
Behaviors are great, but I can't imagine creating a full game using only canned behaviors. So at some point, you will need to add code to do AI, control levels and game state, and other tasks. Here are some pointers to get started with that:
Once you drop a PhysicsController Behavior onto your main Canvas, you can later get a reference to that Physics Controller (the object that contains the simulation context) in code. Suppose your main Canvas is named "LayoutRoot" then you can get a reference as follows:
PhysicsControllerMain _physicsController = LayoutRoot.GetValue(PhysicsControllerMain.PhysicsControllerProperty) as PhysicsControllerMain;
After you have a reference to the PhysicsController, you can modify any of the Farseer Physics Geometry or Body objects by getting a reference throught the PhysicsObjects dictionary:
_physicsController.PhysicsObjects["ball"].GeometryObject.RestitutionCoefficient = 1.3F;
... and you can also get a reference to the oringal XAML UI Element using the uiElement property of the Physics Object:
Ellipse ball = _physicsController.PhysicsObjects["ball"].uiElement as Ellipse; ball.Fill = new SolidColorBrush(Colors.Red);
Feedback and Issues
This is an initial release and my first swing at Behaviors, so I'm sure there will be issues and suggestions. Please let them fly on the Codeplex Forum, and I hope you have fun!
|
 |
|
Comments (8)
|
|
|
|
|
Physics Helper 3: Coming Soon! |
|
Andy's Blog
|
By Andy Beaulieu on
7/10/2009 11:08 AM
|
|
|
|
Silverlight 3 and Blend 3 introduce the concept of Behaviors, which make it easy to add common functionality using drag/drop inside Blend.
I’ve been working on creating a set of Behaviors for the Physics Helper Library, and have made good progress. Using these behaviors, you can very quickly put together physics-based games and simulations with little or no code. (Ok, I don’t really believe in the no-code scenario … but you can do some pretty neat stuff without code). Another new feature in the library is the ability to automatically determine the outline (collision boundary) of raster images (such as a PNG).
I’ll be releasing this updated library soon on Codeplex, but here is a screencast I put together to show the Behaviors in action:
[DOWNLOAD THE VIDEO]
Or click below to view it:

|
 |
|
Comments (4)
|
|
|
|
"Printing" in Silverlight 3 with WriteableBitmap |
|
Andy's Blog
|
By Andy Beaulieu on
7/10/2009 8:30 AM
|
|
|
|
One of the high-profile missing features in Silverlight has been Printing support. If you have ever tried to print a web page containing Silverlight content, what you saw on the printed page may be skewed or even missing altogether! So, what if you wanted to print a portion of your Silverlight screen, or take a “snapshot” image of the Silverlight UI to include in a report or other printable format?
Silverlight 3 can accomplish these scenarios using the WriteableBitmap API. WritableBitmap includes a Render method which can snag all of the pixels of a given UI Element and place them into a buffer for manipulation.
In this demo, I’ll show how to take a “snapshot” of a Silverlight UI screen, upload the image to a web server, and include it in a Report Viewer (RDLC) report. You could easily modify these steps to save the snapshot to an image file on the server, or otherwise manipulate the pixels.
VIEW THE DEMO
DOWNLOAD THE SOURCE
The steps used in the demo are as follows:
1. Render the Silverlight UI to a WriteableBitmap, passing in the UI Element and an arbitrary Transform. In the code below, the content of a Canvas named cnvSource is rendered to the WriteableBitmap. We pass in an empty TranslateTransform simply because one is required by the constructor:
WriteableBitmap bitmap = new WriteableBitmap(cnvSource, new TranslateTransform());
2. Convert the WriteableBitmap pixels to a PNG using Joe Stegman's PNG encoder.
EditableImage imageData = new EditableImage(bitmap.PixelWidth, bitmap.PixelHeight);
for (int y = 0; y < bitmap.PixelHeight; ++y)
{
for (int x = 0; x < bitmap.PixelWidth; ++x)
{
int pixel = bitmap.Pixels[bitmap.PixelWidth * y + x];
imageData.SetPixel(x, y,
(byte)((pixel >> 16) & 0xFF),
(byte)((pixel >> 8) & 0xFF),
(byte)(pixel & 0xFF),
(byte)((pixel >> 24) & 0xFF)
);
}
}
Stream pngStream = imageData.GetStream();
| NOTE that this PNG encoder does NOT include compression! This would be a good optimization to add, but also note that the GZipStream class is not present in Silverlight, so you would need to use an outside compression library such as SharpZipLib.
3. At this point, we have the PNG bytes in a stream, and you could take several approaches to get these bytes up to the server – such as using an Http Handler (ASHX). In this demo, we’ll place the bytes into a hidden field on the ASPX page and post the page back to the server for inclusion in a report. To do this, we’ll translate the PNG bytes into a string using Base64 encoding:
byte[] binaryData = new Byte[pngStream.Length];
long bytesRead = pngStream.Read(binaryData, 0, (int)pngStream.Length);
string base64String =
System.Convert.ToBase64String(binaryData,
0,
binaryData.Length);
// save the encoded PNG bytes to the page
HtmlDocument document = HtmlPage.Document;
HtmlElement txtPNGBytes = document.GetElementById("txtPNGBytes");
txtPNGBytes.SetProperty("value", base64String);
// this calls a js function "postBackPrint" which will cause a postback
HtmlPage.Window.CreateInstance("postBackPrint", new string[] { }); |
4. Now that we have our bytes up on the server, we can decode them and feed them to a ReportViewer (RDLC) report. This will give us a nicely printed format and the ability to export to PDF:
string bytes64 = Request["txtPNGBytes"];
byte[] imageBytes = System.Convert.FromBase64String(bytes64);
DSReportPrintImage ds = new DSReportPrintImage();
DataRow drImage = ds.Tables[0].NewRow();
drImage["ImageBytes"] = imageBytes;
ds.Tables[0].Rows.Add(drImage);
ReportViewer1.LocalReport.ReportPath = "ReportPrintSilverlight.rdlc";
ReportDataSource src = new ReportDataSource("DSReportPrintImage_ImageData", ds.Tables[0]);
ReportViewer1.LocalReport.DataSources.Add(src);
ReportViewer1.LocalReport.Refresh(); |
That’s it! I really think this use of WriteableBitmap as a snapshot/print function will be useful in some of my projects that need to capture the current view of the Silverlight application.
|
 |
|
Comments (28)
|
|
|
|
Improved HitTest Method for Silverlight 3 |
|
Andy's Blog
|
By Andy Beaulieu on
7/10/2009 8:24 AM
|
|
|
|
With the new Silverlight 3 WriteableBitmap class, it’s possible to do pixel-perfect collision detection (a “HitTest”) on bitmap (raster) images. In a previous blog post, I showed how we can do a HitTest on Vector graphics in Silverlight 2. In this blog post, we’ll enhance the collision detection to handle BOTH Vector graphics and Raster graphics in Silverlight 3.
VIEW THE DEMO
DOWNLOAD THE SOURCE
Looking at the demo code, one of the main routines is the CheckCollisionPoint class, which does a HitTest on a UI Element at a specific Point. If the element is an Image, then a WriteableBitmap object is used to check the specific pixel point (this WriteableBitmap is created in the CheckCollision method, shown later.). If the element is not an image, then we assume it is Vector based and we use the VisualTreeHelper class for a hit test:
public bool CheckCollisionPoint(Point pt, FrameworkElement control, FrameworkElement controlElem)
{
if (controlElem is Image)
{
// NOTE that we saved the WB in the Tag object for performance.
// in a real app, you would abstract this in your sprite class.
WriteableBitmap wb = controlElem.Tag as WriteableBitmap;
int width = wb.PixelWidth;
int height = wb.PixelHeight;
double offSetX = Convert.ToDouble(control.GetValue(Canvas.LeftProperty));
double offSetY = Convert.ToDouble(control.GetValue(Canvas.TopProperty));
pt.X = pt.X - offSetX;
pt.Y = pt.Y - offSetY;
int offset = Convert.ToInt32((width * pt.Y) + pt.X);
return (wb.Pixels[offset] != 0);
}
else
{
List<UIElement> hits = System.Windows.Media.VisualTreeHelper.FindElementsInHostCoordinates(pt, controlElem) as List<UIElement>;
return (hits.Contains(controlElem));
}
} |
The CheckCollisionPoint method is used by the CheckCollision method, which checks for a collision between two UI elements. Note that we always want to do a quick Rect.Intersect test on the bounds of the elements before doing the slower per-pixel Hit Test. This method also creates the WriteableBitmap and stores it in the Tag property (you may want to abstract this into a Sprite class in a real application):
private bool CheckCollision(FrameworkElement control1, FrameworkElement controlElem1, FrameworkElement control2, FrameworkElement controlElem2)
{
// first see if sprite rectangles collide
Rect rect1 = UserControlBounds(control1);
Rect rect2 = UserControlBounds(control2);
rect1.Intersect(rect2);
if (rect1 == Rect.Empty)
{
// no collision - GET OUT!
return false;
}
else
{
bool bCollision = false;
Point ptCheck = new Point();
// NOTE that creating the writeablebitmap is a bit intense
// so we will do this once and store results in Tag property
// in a real game, you might abstract this into a Sprite class.
if (controlElem1 is Image)
controlElem1.Tag = GetWriteableBitmap(control1);
if (controlElem2 is Image)
controlElem2.Tag = GetWriteableBitmap(control2);
// now we do a more accurate pixel hit test
for (int x = Convert.ToInt32(rect1.X); x < Convert.ToInt32(rect1.X + rect1.Width); x++)
{
for (int y = Convert.ToInt32(rect1.Y); y < Convert.ToInt32(rect1.Y + rect1.Height); y++)
{
ptCheck.X = x;
ptCheck.Y = y;
if (CheckCollisionPoint(ptCheck, control1, controlElem1))
if (CheckCollisionPoint(ptCheck, control2, controlElem2))
{
bCollision = true;
break;
}
}
if (bCollision) break;
}
return bCollision;
}
} |
A quick note about performance: This method provides a simple way of getting pixel-perfect collision detection in Silverlight 3. But if you have a lot of elements that are colliding simultaneously (without being destroyed), this may not perform well. Also, high velocity objects could pass through each other.
|
 |
|
Comments (10)
|
|
|
|
|
Blend Artboard Exceptions and Loaded Event |
|
Andy's Blog
|
By Andy Beaulieu on
6/3/2009 8:35 AM
|
|
|
|
It can be frustrating when you are coding along in Silverlight, and you open up a UserControl in Blend only to see something like the following:
 An Exception was thrown. InvalidOperationException: HtmlPage_NotEnabled StackTrace InnerException: None
This is often caused by a UserControl that has a Loaded event with some code that isn't happy inside Blend's artboard. That's right - when you preview a UserControl inside Blend, the Loaded event for the control actually fires, and code in that handler is executed! You may have noticed this when you place a StoryBoard.Begin() call in the Loaded event, Blend will actually show the animation on the artboard.
So how do we workaround these exceptions? First, expand the StackTrace arrow, and you'll get some more details. In this case, we can see that the Loaded event for a UserControl named "ucResults" is the culprit:

Now that we know which Loaded event is causing the issue, take a look at the code and see what is going on. In this case, the code is accessing the HtmlPage class - which would not be available to Blend when it hosts the control on the artboard:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// Did the QueryString contain an Email address?
if (HtmlPage.Document.QueryString.Keys.Contains("Email") )
txtEmailTo.Text = HtmlPage.Document.QueryString["Email"].ToString();
}
Luckily, there is a special class, System.ComponentModel.DesignerProperties, which allows us to check at runtime whether we are in Design Mode or not. We can just add a check on this, and if we are in Design Mode, we get out of the Loaded event handler:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (DesignerProperties.GetIsInDesignMode(this))
return;
// Did the QueryString contain an Email address?
if (HtmlPage.Document.QueryString.Keys.Contains("Email") )
txtEmailTo.Text = HtmlPage.Document.QueryString["Email"].ToString();
}
|
 |
|
Comments (1)
|
|
|
|
|
|
Upcoming Silverlight Talks |
|
Andy's Blog
|
By Andy Beaulieu on
5/7/2009 11:00 AM
|
|
|
|
I have a Silverlight Seminar and a webcast coming up at the end of May -if you're available then come and check them out!
GeekSpeak on Silverlight Game Development Wednesday, May 27th 2009 3pm EST The geekSpeak webcast series brings you industry experts in a "talk-radio" format hosted by developer evangelists from Microsoft. These experts share their knowledge and experience about a particular developer technology and are ready to answer your questions in real time during the webcast. To ask a question in advance of the live webcast, or for post-show resources, be sure to visit the geekSpeak blog.
Silverlight Seminar, presented by ACM Saturday, May 30th 2009 8:30am - 4:30pm EST Horizons Computer Learning Center, 6711 Towpath Rd., Suite 100, East Syracuse, NY This will be an all-day Introduction to Silverlight, with Hands-on-Labs.
|
 |
|
Comments (2)
|
|
|
|
|
 |
|
 |
|
|