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 阅读次数:5560