3.在Silverlight中使用Stun2DPhysics
上一篇文章中我们实现了在XNA程序中使用Stun2Dphysics物理引擎,这篇文章继续介绍如何在Silverlight中使用这个引擎。
首先创建一个新Silverlight应用程序,我命名为Stun2DPhysics4SLDemo,默认此应用程序承载在web应用程序中,名称为Stun2DPhysics4SLDemo.Web。
然后创建一个Silverlight类库,这个类库就是用于Silverlight的2D物理引擎,我命名为Stun2DPhysics4SL,代码与1.质点运动学和Stun2DPhysics引擎中创建的物理引擎Stun2Dphysics完全相同,完全照搬即可(是不是同样的物理引擎无需复制就可以同时用于XNA和Silverlight,好像可以,好像可以使用#if(Silverlight)之类的条件编译实现,但我的尝试没有成功,所以目前还是两个物理引擎:一个用于XNA的Stun2Dphysics,一个用于Silverlight的Stun2Dphysics4SL)。
引擎结构截图如下:

从截图中可以看到,有一点不同,在Silverlight类库中的Mathematics命名空间编写了自定义的Vector2结构,而在XNA中使用的Stun2Dphysics中Vector2是XNA框架自带的,不需要自己创建。自己编写Vector2结构有点难,你参考一下XNA帮助文件的Vector2的内容,这个结构实现了近20个公有方法,并且重载了+、-、*、/等运算符。具体代码如下:
using System;
namespace Stun2DPhysics4SL.Mathematics
{
public struct Vector2
{
private static Vector2 _one = new Vector2(1f, 1f);
private static Vector2 _unitX = new Vector2(1f, 0f);
private static Vector2 _unitY = new Vector2(0f, 1f);
private static Vector2 _zero = new Vector2(0f, 0f);
public float X;
public float Y;
public Vector2(float x, float y)
{
X = x;
Y = y;
}
public Vector2(float value)
{
X = Y = value;
}
public static Vector2 Zero
{
get { return _zero; }
}
public static Vector2 One
{
get { return _one; }
}
public static Vector2 UnitX
{
get { return _unitX; }
}
public static Vector2 UnitY
{
get { return _unitY; }
}
public override string ToString()
{
return string.Format("{{X:{0} Y:{1}}}", new object[] {X.ToString(), Y.ToString()});
}
public bool Equals(Vector2 other)
{
if (X == other.X)
{
return (Y == other.Y);
}
return false;
}
public override bool Equals(object obj)
{
bool flag = false;
if (obj is Vector2)
{
flag = Equals((Vector2) obj);
}
return flag;
}
public override int GetHashCode()
{
return (X.GetHashCode() + Y.GetHashCode());
}
public float Length()
{
float num = (X*X) + (Y*Y);
return (float) Math.Sqrt(num);
}
public float LengthSquared()
{
return ((X*X) + (Y*Y));
}
public static float Distance(Vector2 value1, Vector2 value2)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
float num3 = (num2*num2) + (num*num);
return (float) Math.Sqrt(num3);
}
public static void Distance(ref Vector2 value1, ref Vector2 value2, out float result)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
float num3 = (num2*num2) + (num*num);
result = (float) Math.Sqrt(num3);
}
public static float DistanceSquared(Vector2 value1, Vector2 value2)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
return ((num2*num2) + (num*num));
}
public static void DistanceSquared(ref Vector2 value1, ref Vector2 value2, out float result)
{
float num2 = value1.X - value2.X;
float num = value1.Y - value2.Y;
result = (num2*num2) + (num*num);
}
public static float Dot(Vector2 value1, Vector2 value2)
{
return ((value1.X*value2.X) + (value1.Y*value2.Y));
}
public static void Dot(ref Vector2 value1, ref Vector2 value2, out float result)
{
result = (value1.X*value2.X) + (value1.Y*value2.Y);
}
public void Normalize()
{
float num2 = (X*X) + (Y*Y);
float num = 1f/((float) Math.Sqrt(num2));
X *= num;
Y *= num;
}
public static Vector2 Normalize(Vector2 value)
{
Vector2 vector;
float num2 = (value.X*value.X) + (value.Y*value.Y);
float num = 1f/((float) Math.Sqrt(num2));
vector.X = value.X*num;
vector.Y = value.Y*num;
return vector;
}
public static void Normalize(ref Vector2 value, out Vector2 result)
{
float num2 = (value.X*value.X) + (value.Y*value.Y);
float num = 1f/((float) Math.Sqrt(num2));
result.X = value.X*num;
result.Y = value.Y*num;
}
public static Vector2 Min(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = (value1.X < value2.X) ? value1.X : value2.X;
vector.Y = (value1.Y < value2.Y) ? value1.Y : value2.Y;
return vector;
}
public static void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = (value1.X < value2.X) ? value1.X : value2.X;
result.Y = (value1.Y < value2.Y) ? value1.Y : value2.Y;
}
public static Vector2 Max(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = (value1.X > value2.X) ? value1.X : value2.X;
vector.Y = (value1.Y > value2.Y) ? value1.Y : value2.Y;
return vector;
}
public static void Max(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = (value1.X > value2.X) ? value1.X : value2.X;
result.Y = (value1.Y > value2.Y) ? value1.Y : value2.Y;
}
public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max)
{
Vector2 vector;
float x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
float y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
vector.X = x;
vector.Y = y;
return vector;
}
public static void Clamp(ref Vector2 value1, ref Vector2 min, ref Vector2 max, out Vector2 result)
{
float x = value1.X;
x = (x > max.X) ? max.X : x;
x = (x < min.X) ? min.X : x;
float y = value1.Y;
y = (y > max.Y) ? max.Y : y;
y = (y < min.Y) ? min.Y : y;
result.X = x;
result.Y = y;
}
public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount)
{
Vector2 vector;
vector.X = value1.X + ((value2.X - value1.X)*amount);
vector.Y = value1.Y + ((value2.Y - value1.Y)*amount);
return vector;
}
public static void Lerp(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)
{
result.X = value1.X + ((value2.X - value1.X)*amount);
result.Y = value1.Y + ((value2.Y - value1.Y)*amount);
}
public static Vector2 Barycentric(Vector2 value1, Vector2 value2, Vector2 value3, float amount1, float amount2)
{
Vector2 vector;
vector.X = (value1.X + (amount1*(value2.X - value1.X))) + (amount2*(value3.X - value1.X));
vector.Y = (value1.Y + (amount1*(value2.Y - value1.Y))) + (amount2*(value3.Y - value1.Y));
return vector;
}
public static void Barycentric(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, float amount1,
float amount2, out Vector2 result)
{
result.X = (value1.X + (amount1*(value2.X - value1.X))) + (amount2*(value3.X - value1.X));
result.Y = (value1.Y + (amount1*(value2.Y - value1.Y))) + (amount2*(value3.Y - value1.Y));
}
public static Vector2 SmoothStep(Vector2 value1, Vector2 value2, float amount)
{
Vector2 vector;
amount = (amount > 1f) ? 1f : ((amount < 0f) ? 0f : amount);
amount = (amount*amount)*(3f - (2f*amount));
vector.X = value1.X + ((value2.X - value1.X)*amount);
vector.Y = value1.Y + ((value2.Y - value1.Y)*amount);
return vector;
}
public static void SmoothStep(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)
{
amount = (amount > 1f) ? 1f : ((amount < 0f) ? 0f : amount);
amount = (amount*amount)*(3f - (2f*amount));
result.X = value1.X + ((value2.X - value1.X)*amount);
result.Y = value1.Y + ((value2.Y - value1.Y)*amount);
}
public static Vector2 CatmullRom(Vector2 value1, Vector2 value2, Vector2 value3, Vector2 value4, float amount)
{
Vector2 vector;
float num = amount*amount;
float num2 = amount*num;
vector.X = 0.5f*
((((2f*value2.X) + ((-value1.X + value3.X)*amount)) +
(((((2f*value1.X) - (5f*value2.X)) + (4f*value3.X)) - value4.X)*num)) +
((((-value1.X + (3f*value2.X)) - (3f*value3.X)) + value4.X)*num2));
vector.Y = 0.5f*
((((2f*value2.Y) + ((-value1.Y + value3.Y)*amount)) +
(((((2f*value1.Y) - (5f*value2.Y)) + (4f*value3.Y)) - value4.Y)*num)) +
((((-value1.Y + (3f*value2.Y)) - (3f*value3.Y)) + value4.Y)*num2));
return vector;
}
public static void CatmullRom(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, ref Vector2 value4,
float amount, out Vector2 result)
{
float num = amount*amount;
float num2 = amount*num;
result.X = 0.5f*
((((2f*value2.X) + ((-value1.X + value3.X)*amount)) +
(((((2f*value1.X) - (5f*value2.X)) + (4f*value3.X)) - value4.X)*num)) +
((((-value1.X + (3f*value2.X)) - (3f*value3.X)) + value4.X)*num2));
result.Y = 0.5f*
((((2f*value2.Y) + ((-value1.Y + value3.Y)*amount)) +
(((((2f*value1.Y) - (5f*value2.Y)) + (4f*value3.Y)) - value4.Y)*num)) +
((((-value1.Y + (3f*value2.Y)) - (3f*value3.Y)) + value4.Y)*num2));
}
public static Vector2 Hermite(Vector2 value1, Vector2 tangent1, Vector2 value2, Vector2 tangent2, float amount)
{
Vector2 vector;
float num = amount*amount;
float num2 = amount*num;
float num6 = ((2f*num2) - (3f*num)) + 1f;
float num5 = (-2f*num2) + (3f*num);
float num4 = (num2 - (2f*num)) + amount;
float num3 = num2 - num;
vector.X = (((value1.X*num6) + (value2.X*num5)) + (tangent1.X*num4)) + (tangent2.X*num3);
vector.Y = (((value1.Y*num6) + (value2.Y*num5)) + (tangent1.Y*num4)) + (tangent2.Y*num3);
return vector;
}
public static void Hermite(ref Vector2 value1, ref Vector2 tangent1, ref Vector2 value2, ref Vector2 tangent2,
float amount, out Vector2 result)
{
float num = amount*amount;
float num2 = amount*num;
float num6 = ((2f*num2) - (3f*num)) + 1f;
float num5 = (-2f*num2) + (3f*num);
float num4 = (num2 - (2f*num)) + amount;
float num3 = num2 - num;
result.X = (((value1.X*num6) + (value2.X*num5)) + (tangent1.X*num4)) + (tangent2.X*num3);
result.Y = (((value1.Y*num6) + (value2.Y*num5)) + (tangent1.Y*num4)) + (tangent2.Y*num3);
}
public static Vector2 Negate(Vector2 value)
{
Vector2 vector;
vector.X = -value.X;
vector.Y = -value.Y;
return vector;
}
public static void Negate(ref Vector2 value, out Vector2 result)
{
result.X = -value.X;
result.Y = -value.Y;
}
public static Vector2 Add(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X + value2.X;
vector.Y = value1.Y + value2.Y;
return vector;
}
public static void Add(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X + value2.X;
result.Y = value1.Y + value2.Y;
}
public static Vector2 Subtract(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X - value2.X;
vector.Y = value1.Y - value2.Y;
return vector;
}
public static void Subtract(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X - value2.X;
result.Y = value1.Y - value2.Y;
}
public static Vector2 Multiply(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X*value2.X;
vector.Y = value1.Y*value2.Y;
return vector;
}
public static void Multiply(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X*value2.X;
result.Y = value1.Y*value2.Y;
}
public static Vector2 Multiply(Vector2 value1, float scaleFactor)
{
Vector2 vector;
vector.X = value1.X*scaleFactor;
vector.Y = value1.Y*scaleFactor;
return vector;
}
public static void Multiply(ref Vector2 value1, float scaleFactor, out Vector2 result)
{
result.X = value1.X*scaleFactor;
result.Y = value1.Y*scaleFactor;
}
public static Vector2 Divide(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X/value2.X;
vector.Y = value1.Y/value2.Y;
return vector;
}
public static void Divide(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X/value2.X;
result.Y = value1.Y/value2.Y;
}
public static Vector2 Divide(Vector2 value1, float divider)
{
Vector2 vector;
float num = 1f/divider;
vector.X = value1.X*num;
vector.Y = value1.Y*num;
return vector;
}
public static void Divide(ref Vector2 value1, float divider, out Vector2 result)
{
float num = 1f/divider;
result.X = value1.X*num;
result.Y = value1.Y*num;
}
public static Vector2 operator -(Vector2 value)
{
Vector2 vector;
vector.X = -value.X;
vector.Y = -value.Y;
return vector;
}
public static bool operator ==(Vector2 value1, Vector2 value2)
{
if (value1.X == value2.X)
{
return (value1.Y == value2.Y);
}
return false;
}
public static bool operator !=(Vector2 value1, Vector2 value2)
{
if (value1.X == value2.X)
{
return (value1.Y != value2.Y);
}
return true;
}
public static Vector2 operator +(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X + value2.X;
vector.Y = value1.Y + value2.Y;
return vector;
}
public static Vector2 operator -(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X - value2.X;
vector.Y = value1.Y - value2.Y;
return vector;
}
public static Vector2 operator *(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X*value2.X;
vector.Y = value1.Y*value2.Y;
return vector;
}
public static Vector2 operator *(Vector2 value, float scaleFactor)
{
Vector2 vector;
vector.X = value.X*scaleFactor;
vector.Y = value.Y*scaleFactor;
return vector;
}
public static Vector2 operator *(float scaleFactor, Vector2 value)
{
Vector2 vector;
vector.X = value.X*scaleFactor;
vector.Y = value.Y*scaleFactor;
return vector;
}
public static Vector2 operator /(Vector2 value1, Vector2 value2)
{
Vector2 vector;
vector.X = value1.X/value2.X;
vector.Y = value1.Y/value2.Y;
return vector;
}
public static Vector2 operator /(Vector2 value1, float divider)
{
Vector2 vector;
float num = 1f/divider;
vector.X = value1.X*num;
vector.Y = value1.Y*num;
return vector;
}
}
}
完成物理引擎后,就可以开始编写Silverlight程序代码了,首先添加Silverlight用户控件,命名为Box1,然后添加一个Rectangle,边框颜色为黑色,宽度为2,填充颜色为白色,在Silverlight中画矩形框可比XNA方便多了。
Box1.xmal的代码如下:
<UserControl x:Class="Stun2DPhysics4SLDemo.Box1"
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">
<Canvas x:Name="LayoutRoot" Background="Transparent">
<Rectangle Height="32" Name="box1" Stroke="Black" StrokeThickness="2" Width="32" Fill="White" />
</Canvas>
</UserControl>
Box1.xmal.cs中添加了引擎中的Body类,实现了物理属性,代码为:
using System;
using System.Windows.Controls;
using Stun2DPhysics4SL;
using Stun2DPhysics4SL.Dynamics;
namespace Stun2DPhysics4SLDemo
{
public partial class Box1 : UserControl
{
public Body Body { get; set; }
public Box1()
{
InitializeComponent();
Body = new Body();
}
public void Load(PhysicsSimulator physicsSimulator)
{
physicsSimulator.Add(Body);
}
public void Update()
{
this.SetValue(Canvas.LeftProperty, Convert.ToDouble(Body.Position.X));
this.SetValue(Canvas.TopProperty, Convert.ToDouble(Body.Position.Y));
}
}
}
用类似的方法创建了另一个用户控件Box2,它与Box1的区别在于绘制的一张纹理,后台代码是一样的,这就意味着有必要进行代码重构,进行封装创建一个基类,我会在下一个Demo中实现。
应用程序主类MainPage.xaml.cs后台代码为:
using System;
using System.Windows.Controls;
using System.Windows.Media;
using Stun2DPhysics4SL;
using Stun2DPhysics4SL.Mathematics;
namespace Stun2DPhysics4SLDemo
{
public partial class MainPage : UserControl
{
PhysicsSimulator physicsSimulator;
bool isRunning = false ;
public MainPage()
{
InitializeComponent();
physicsSimulator = new PhysicsSimulator();
box1.Load(physicsSimulator);
box1.Body.Acceleration = new Vector2(0, 100);
box1.Body.LinearVelocity = new Vector2(150, 0);
box2.Load(physicsSimulator);
box2.Body.Position = new Vector2(736,0);
box2.Body.LinearVelocity = new Vector2(-150, 0);
box2.Body.Acceleration = new Vector2(0, 200);
}
private void CompositionTarget_Rendering(object sender, EventArgs e)
{
physicsSimulator.Update(0.0167f);
box1.Update();
box2.Update();
// 处理物体在边界上的碰撞,以后会通过引擎中的碰撞检测实现
if (box1.Body.Position.X > 768 || box1.Body.Position.X < 0)
box1.Body.LinearVelocity.X *= -1;
if (box1.Body.Position.Y > 448 || box1.Body.Position.Y < 0)
box1.Body.LinearVelocity.Y *= -1;
if (box2.Body.Position.X > 736 || box2.Body.Position.X < 0)
box2.Body.LinearVelocity.X *= -1;
if (box2.Body.Position.Y > 416 || box2.Body.Position.Y < 0)
box2.Body.LinearVelocity.Y *= -1;
}
private void btnStart_Click(object sender, System.Windows.RoutedEventArgs e)
{
if (!isRunning)
{
btnStart.Content = "暂停";
CompositionTarget.Rendering += new EventHandler(CompositionTarget_Rendering);
isRunning = true;
}
else
{
btnStart.Content = "继续";
CompositionTarget.Rendering -= new EventHandler(CompositionTarget_Rendering);
isRunning = false;
}
}
}
}
主要的工作就是:在初始化时创建物理引擎和Box对象,设置Box对象的初位置、初速度和加速度,然后在循环中更新物理引擎,通过更新后的Body属性更新Box的位置。
文件下载(已下载 1037 次)发布时间:2011/6/3 上午9:31:58 阅读次数:6111
