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

2006 - 2024,推荐分辨率 1024*768 以上,推荐浏览器 Chrome、Edge 等现代浏览器,截止 2021 年 12 月 5 日的访问次数:1872 万 9823 站长邮箱

沪 ICP 备 18037240 号-1

沪公网安备 31011002002865 号