Сегодня я вам покажу, как можно довольно просто добавить физику в Silverlight-проект. Рассмотрим это на небольшом примере с использованием физического движка
Farseer Physics, распространяющегося совершенно бесплатно.
До того, как мы приступим к созданию приложения, нам потребуется скачать движок Farseer Physics Silverlight, доступный на Codeplex. В этом примере я буду использовать версию 2.1.3 – самую свежую из доступных. Также нам понадобится
Physics Helper, сильно упрощающий добавление физических объектов в проект с Farseer Physics.
Для самой разработки нам потребуются следующие инструменты:
Все DLL-файлы, которые понадобятся для нашего проекта, вы можете скачать одним архивом
здесь.
Итак, приступим. Сделаем все за 7 простых шагов.
- Открываем Visual Studio и создаем новый Silverlight-проект. У меня он называется SilverlightPhysics:
- Копируем 3 нужных DLL-файла в какую-нибудь папку. Теперь нужно подключить эти файлы к проекту. В окне Solution Explorer нажимаем правой кнопкой мыши на папке References и выбираем пункт “Add reference”:
Выбираем наши файлы на закладке Browse и жмем OK:
Аналогичным образом добавим System.Windows.Interactivity из Expression Blend 3 SDK. Проверяем:
- Открываем файл MainPage.xaml. В этом примере удобнее будет использовать Canvas вместо Grid, поэтому заменим тег <Grid> на <Canvas>. Добавим необходимые объекты с помощью XAML-кода:
<UserControl
x:Class="SilverlightPhysics.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="640" d:DesignHeight="480">
<Canvas x:Name="LayoutRoot" Background="Black">
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="215" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="365" Canvas.Top="433"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="230" Canvas.Top="403"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="283"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="313"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="313"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="343"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="343"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="343"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="335" Canvas.Top="373"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="305" Canvas.Top="373"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="275" Canvas.Top="373"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="245" Canvas.Top="373"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="350" Canvas.Top="403"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="320" Canvas.Top="403"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="290" Canvas.Top="403"/>
<Rectangle Fill="White" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Left="260" Canvas.Top="403"/>
<Rectangle Fill="White" StrokeThickness="2" Height="29" Width="640" Canvas.Left="0" Canvas.Top="475"/>
<Ellipse Fill="Red" Stroke="#FFB9B9B9" StrokeThickness="2" Height="25" Width="25" Canvas.Top="173" Canvas.Left="255"/>
</Canvas>
</UserControl>
Если запустить проект на данном этапе, то можно будет увидеть большой прямоугольник для будущей платформы, небольшую пирамидку из белых кубиков и красный шарик. Никакой физики у объектов пока нет:

- Добавим два пространства имен для легкого обращения к физическому движку и System.Windows.Interactivity:
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:pb="clr-namespace:Spritehand.PhysicsBehaviors;assembly=Spritehand.PhysicsBehaviors"
Теперь мы должны определить PhysicsController, который можно сделать из любого контейнера XAML. В нашем примере это будет Canvas, так как именно в нем содержатся все нужные нам объекты – кубики и шарик. Для этого в XAML-код Canvas добавляем соответствующий узел поведения (как ужасно это звучит на русском :) ). Там же включим свойство MousePickEnabled, чтобы можно было с помощью мыши перетаскивать любой объект:
<Canvas x:Name="LayoutRoot" Background="Black">
<i:Interaction.Behaviors>
<pb:PhysicsControllerBehavior MousePickEnabled="True"/>
</i:Interaction.Behaviors>
Делаем платформу. Сначала нам потребуется добавить закрывающийся тег для самого нижнего прямоугольника. Наша платформа должна быть статичной и никуда не падать, поэтому мы добавим соответствующее свойство IsStatic и установим его значение в True. Код для этого прямоугольника станет выглядеть следующим образом:
<Rectangle Fill="White" StrokeThickness="2" Height="29" Width="640" Canvas.Left="0" Canvas.Top="475">
<i:Interaction.Behaviors>
<pb:PhysicsObjectBehavior IsStatic="True"/>
</i:Interaction.Behaviors>
</Rectangle>
Соответствующим образом меняем код для всех маленьких прямоугольников и круга. Только теперь уже свойство IsStatic добавлять не надо, потому что эти объекты должны быть динамичны и подвержены законам физики. Финальный код можно посмотреть в готовом проекте
Да, данный движок не идеален:
Зато он бесплатен, довольно прост в использовании и позволяет легко добавить физику даже в игры Xbox 360 (сделанные на XNA).
Данный пример был достаточно простым. Если проявить фантазию и приложить немного усилий, то можно сделать что-нибудь гораздо более впечатляющее. Например, добавить физику жидкости, взрывы и т.п. Буду ждать ваших проектов ;)
комментарии (11)
Да, конечно, код небольшой, но листать неудобно. В остальном мне статья понравилась.
Как вставить рабочий вариант сюда — не знаю
jeffblankenburg.com/2009/12/day-22-using-farseer-physics-engine-in.aspx