This project has moved and is read-only. For the latest updates, please go here.

WPF, Surface, multitouch

Jul 20, 2011 at 11:39 AM

Hi... I would very much like a farseer wrapper that actually support WPF, as I need physics for a Surface-project. I've tried converting the last PhysicsHelper that supported WPF, but that rendered multitouch and the Surface SDK useless.

So I can see this uses a newer version of the Farseer engine, why I got my hopes up a little.

But I really cant get this to work in WPF with .net 4.0. Can you make a sample project?

Jul 20, 2011 at 12:44 PM
Edited Jul 20, 2011 at 12:46 PM

Oh, it does'nt support WPF at all. Thought so after reading this: http://liserdartsgames.com/LocalResources/XamlPhysics/Index.html#/SampleMenu.xaml

But I can see it requires the Silverlight System.windows.dll 2.0.5.0, not supported by WPF...

Any plans to do it?

Jul 20, 2011 at 8:17 PM

Xml Physics does support WPF it's just a matter of moving the code to a new project instead of the Silverlight one.

I should be able to crate a release for you sometime today.

Jul 20, 2011 at 10:55 PM

That would be great, thank you! I hope it passes all touch-events...

Jul 21, 2011 at 8:17 AM

The release is ready.

http://xamlphysics.codeplex.com/releases/view/70412

I created a sample project with just the "Simple Bodies" sample to get you started. The code is really very similar. Using the Silverlight samples in a WPF project should be very easy.

Let me know how it works and if there is anything else I can help you with. 

Jul 21, 2011 at 10:06 AM
Edited Jul 21, 2011 at 12:16 PM

Thank you. But...

In VS2010 I created a default 4.0 project and referenced the two dll's. I copy/paste the sample code, and my designview show the boxes, no errors at all. Debugging it however just left the boxes in place - no physics applied. I tried another piece of sample code from the documentation, nothing. All just stayed in place.

Then I tried Blend (which usually peeps over the slightest things), and sure enough, it complained about the library not being strongly signed. I guess VS2010 is more tolerant to that sort of behavior, lol.

Using the source directly indicates same problem - LiserdArts.snk - network path not found... 172 errors and 14 warnings... Turning signing off seems to do the trick ;)

But everything still stays in place when I debug. I can see in your code, that you use GameLoop.vb to initialize the physics. Can you turn that into a DLL exposing GameLoop.Start() ... I can see it is rather tied up with viewer.vb, but I hope GameLoop_Tick and Tick() can be integrated in the DLL (have now idea about VB at all). Tick() does have hardcoded objectnames though...

Jul 21, 2011 at 11:11 PM

Which assembly wasn't signed? All of them but the sample projects should be.

You are on the right track. The GameLoop class is used to run the PhysicalBox by calling a few things on each tick.

I created another release for you that makes this a whole lot easier. Basically I moved GameLoop to XamlPhysics and XamlPhysics.WPF and added a Clock property to PhysicalBox. I've had this on my to do list for a while actually. Now you can write the GameLoop right in the xaml like this.

<s:SurfaceWindow x:Class="SurfaceApplication2.SurfaceWindow1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
   xmlns:Physics="clr-namespace:XamlPhysics.WPF;assembly=XamlPhysics.WPF"
    Title="SurfaceApplication1" Height="768" Width="1024" Foreground="#FF009B00">

    <Canvas Background="#FF980000" Width="1024" Height="768">
        <Physics:PhysicalBox x:Name="PhysicalBox">
            <Physics:PhysicalBox.Clock>
                <Physics:GameLoop />
            </Physics:PhysicalBox.Clock>
            <Rectangle Canvas.Top="100" Canvas.Left="0" Width="400" Height="30" Fill="Black">
                <Physics:PhysicalBox.Body>
                    <Physics:RectangleBody IsStatic="True" />
                </Physics:PhysicalBox.Body>
            </Rectangle>
            <Rectangle Canvas.Top="0" Canvas.Left="20" Width="10" Height="10" Fill="Black">
                <Physics:PhysicalBox.Body>
                    <Physics:RectangleBody Mass="10" />
                </Physics:PhysicalBox.Body>
            </Rectangle>
        </Physics:PhysicalBox>
    </Canvas>
</s:SurfaceWindow>

You will still have to make a call to start the clock like this

PhysicalBox.Clock.Start()

By they way you might find this tool useful in the future. http://www.developerfusion.com/tools/convert/vb-to-csharp/

Jul 22, 2011 at 9:39 AM

Works!

Still had problems with assembly signings - (protection level too high), but turning it off removed all errors in the project. It is very much like the Physics Helper, but up to date for WPF.

Have you been using the surface SDK as your example above suggest? I'm laying out my strategy for passing touchevents into farseer, and just now I noticed a file in XAML Physics called 'MouseDrag'... hmmmm. I'm guessing I somehow could duplicate and convert the stuff going on in there (albeit VB) to touch/multitouch. Does that hook directly to the presentation layer or is there something in between the very object and the Xaml Physics constructor? Do you have any thoughts on my approach.

Again, thx for all your help!

Jul 22, 2011 at 1:04 PM
Edited Jul 22, 2011 at 2:32 PM

Here's what I've been trying to do so far... it does'nt work (yet), but I think this should be achievable. The class needs to be in the Xaml.Physics.WPF project, because TouchEventArgs is not possible in Silverlight.

Problems:

1 - Initializing and starting basic touchcapture and touchdevice. Been looking at this:
http://msdn.microsoft.com/en-us/library/system.windows.uielement.capturetouch.aspx
http://msdn.microsoft.com/en-us/library/system.windows.input.touchdevice.aspx

Also found an excerpt here (page 150+): http://books.google.dk/books?id=F-gMZkAlUDUC&pg=PA152&lpg=PA152&dq=touchpoint+point+conversion+vb&source=bl&ots=qz9Qjm0ed-&sig=3jqvzfjnqKmcZyB85jVud_0pWkY&hl=da&ei=s2kpTompL8zo-ga96o3eBg&sa=X&oi=book_result&ct=result&resnum=2&ved=0CCAQ6AEwAQ#v=onepage&q&f=false

But I ran out of VB-skills, I guess. And I do think this needs to be in your wrapper like the rest, why I have'nt tried in C# (well, did try using the VB->C# converter you suggested, but it does not render mousedrag.vb properly). Fixed.

2 - Converting TouchPoint to Point. Fixed.

3 - Surface benefits. Not actually a problem, but a possibilty later on. Surface recognize touchdirections. So if I rotate my finger on the same point it does open some cool possibilities with physics.

I also noticed that applying mass to objects can really do some crazy things when interacting with mouse...

I've been talking about Physics in WPF in conjunction with Surface on their forums, which you may be interested in: http://social.msdn.microsoft.com/Forums/en/surfaceappdevelopment/thread/4dee6f8e-c785-401c-a8c5-88f4e9a2a16b

TouchDrag.vb:

'Copyright (c) 2011, Nicholas Avery
'Licensed under the Microsoft Public License (Ms-PL)
'you may not use this file except in compliance with the License.
'You may obtain a copy of the license at http://xamlphysics.codeplex.com/license

''' <summary>
''' Rewrite for Touch by Jesper Johansen
''' Catches touch events and allows dragging and dropping bodies
''' </summary>
''' 
Public Class TouchDrag
    Inherits Canvas

    ''' <summary>
    ''' The maximum constraint force that can be exerted to move the candidate body.
    ''' </summary>
    Public Property MaxForce() As Double = 1

    ''' <summary>
    ''' The response speed.
    ''' </summary>
    Public Property Frequency() As Double = 5

    Public Property Breakpoint() As Double = Single.MaxValue

    ''' <summary>
    ''' The damping ratio. 0 = no damping, 1 = critical damping.
    ''' </summary>
    Public Property DampingRatio() As Double = 0.7


    Dim SelectedBody As PhysicalBody
    Dim Joint As FarseerPhysics.Dynamics.Joints.FixedMouseJoint

    Private Sub TouchTrap_Down(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchDown
        If SelectedBody IsNot Nothing Then Return

        SelectedBody = PhysicalBox.GetBody(e.OriginalSource)
        If SelectedBody Is Nothing Then Return
        If SelectedBody.Body Is Nothing Then
            SelectedBody = Nothing
            Return
        End If

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody.Box)
        Joint = New FarseerPhysics.Dynamics.Joints.FixedMouseJoint(SelectedBody.Body, SelectedBody.Box.PointToMeter(New Point(TouchPoint.Position.X, TouchPoint.Position.Y)))
        Joint.MaxForce = MaxForce
        Joint.Frequency = Frequency
        Joint.Breakpoint = Breakpoint
        Joint.DampingRatio = DampingRatio
        SelectedBody.Box.World.AddJoint(Joint)

        e.Handled = True
        CaptureTouch()
    End Sub

    Private Sub TouchTrap_Up(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchUp
        If SelectedBody Is Nothing Then Return
        e.Handled = True
        ReleaseMouseCapture()

        SelectedBody.Box.World.RemoveJoint(Joint)
        SelectedBody = Nothing
        Joint = Nothing
    End Sub

    Private Sub TouchTrap_Move(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchMove
        If SelectedBody Is Nothing Then Return

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody.Box)
        Joint.WorldAnchorB = SelectedBody.Box.PointToMeter(New Point(TouchPoint.Position.X, TouchPoint.Position.Y))
        System.Diagnostics.Debug.WriteLine(Joint.WorldAnchorB.ToString)
    End Sub
End Class
Jul 22, 2011 at 2:41 PM
Edited Jul 22, 2011 at 4:23 PM

Breakthrough! I only had to fix the touchpoint conversion, which was quite easy, actually, and then it works! Running it with the Surface Simulator I can interact with objects with touchpoints.

This have shown some new problems.

1 - Joint. If the touch get moved too fast, so the touchpoint is actually outside the object, makes the object 'hang' in space. As soon as I move the touch back on the object it moves again. So there is somehow a connection between the object selected and the touchpoint, rather than just the newly created joint and the object.

2 - Multitouch. This does'nt work properly. If I hold on to an object with one touch, and touches another object with a second touch, it moves the first object. Seems it creates a new joint for the first object selected. I guess we need to take the TouchDevice ID in account somehow... see code below:

3 - Simulator. I think this is a bug in the Surface simulator... If I fix a touch to an object and make a few other touches, after a while it disregards the initial touch (which is still there), and just run after the cursor floating (not 'touching' per say). I'm using an old computer and have no access to multitouch hardware, so I need to find a test-space.

'Copyright (c) 2011, Nicholas Avery
'Licensed under the Microsoft Public License (Ms-PL)
'you may not use this file except in compliance with the License.
'You may obtain a copy of the license at http://xamlphysics.codeplex.com/license

''' <summary>
''' Rewrite for Touch by Jesper Johansen
''' Catches touch events and allows dragging and dropping bodies
''' </summary>
''' 
Public Class TouchDrag
    Inherits Canvas

    ''' <summary>
    ''' The maximum constraint force that can be exerted to move the candidate body.
    ''' </summary>
    Public Property MaxForce() As Double = 1

    ''' <summary>
    ''' The response speed.
    ''' </summary>
    Public Property Frequency() As Double = 5

    Public Property Breakpoint() As Double = Single.MaxValue

    ''' <summary>
    ''' The damping ratio. 0 = no damping, 1 = critical damping.
    ''' </summary>
    Public Property DampingRatio() As Double = 0.7
    Private TouchCollection As New Dictionary(Of Integer, FarseerPhysics.Dynamics.Joints.Joint)()

    Dim SelectedBody As PhysicalBody
    Dim Joint As FarseerPhysics.Dynamics.Joints.FixedMouseJoint

    Private Sub TouchTrap_Down(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchDown
        If SelectedBody IsNot Nothing Then Return

        SelectedBody = PhysicalBox.GetBody(e.OriginalSource)
        If SelectedBody Is Nothing Then Return
        If SelectedBody.Body Is Nothing Then
            SelectedBody = Nothing
            Return
        End If

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody.Box)
        Joint = New FarseerPhysics.Dynamics.Joints.FixedMouseJoint(SelectedBody.Body, SelectedBody.Box.PointToMeter(TouchPoint.Position.X, TouchPoint.Position.Y))
        Joint.MaxForce = MaxForce
        Joint.Frequency = Frequency
        Joint.Breakpoint = Breakpoint
        Joint.DampingRatio = DampingRatio
        SelectedBody.Box.World.AddJoint(Joint)
        TouchCollection(e.TouchDevice.Id) = Joint
        e.Handled = True

    End Sub

    Private Sub TouchTrap_Up(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchUp
        If SelectedBody Is Nothing Then Return
        Dim element As FarseerPhysics.Dynamics.Joints.Joint = TouchCollection(e.TouchDevice.Id)
        e.Handled = True
        SelectedBody.Box.World.RemoveJoint(Joint)
        SelectedBody = Nothing
        Joint = Nothing
        TouchCollection.Remove(e.TouchDevice.Id)
    End Sub

    Private Sub TouchTrap_Move(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchMove
        If SelectedBody Is Nothing Then Return
        Dim element As FarseerPhysics.Dynamics.Joints.Joint = TouchCollection(e.TouchDevice.Id)

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody.Box)
        Joint.WorldAnchorB = SelectedBody.Box.PointToMeter(New Point(TouchPoint.Position.X, TouchPoint.Position.Y))
        System.Diagnostics.Debug.WriteLine(Joint.WorldAnchorB.ToString)
    End Sub
End Class
'Copyright (c) 2011, Nicholas Avery
'Licensed under the Microsoft Public License (Ms-PL)
'you may not use this file except in compliance with the License.
'You may obtain a copy of the license at http://xamlphysics.codeplex.com/license

''' <summary>
''' Rewrite for Touch by Jesper Johansen
''' Catches touch events and allows dragging and dropping bodies
''' </summary>
'''
Public Class TouchDrag
    Inherits Canvas

    ''' <summary>
    ''' The maximum constraint force that can be exerted to move the candidate body.
    ''' </summary>
    Public Property MaxForce() As Double = 1

    ''' <summary>
    ''' The response speed.
    ''' </summary>
    Public Property Frequency() As Double = 5

    Public Property Breakpoint() As Double = Single.MaxValue

    ''' <summary>
    ''' The damping ratio. 0 = no damping, 1 = critical damping.
    ''' </summary>
    Public Property DampingRatio() As Double = 0.7
    Private TouchCollection As New Dictionary(Of Integer, FarseerPhysics.Dynamics.Joints.Joint)()

    Dim SelectedBody As PhysicalBody
    Dim Joint As FarseerPhysics.Dynamics.Joints.FixedMouseJoint

    Private Sub TouchTrap_Down(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchDown
        If SelectedBody IsNot Nothing Then Return

        SelectedBody = PhysicalBox.GetBody(e.OriginalSource)
        If SelectedBody Is Nothing Then Return
        If SelectedBody.Body Is Nothing Then
            SelectedBody = Nothing
            Return
        End If

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody)
        Joint = New FarseerPhysics.Dynamics.Joints.FixedMouseJoint(SelectedBody.Body, SelectedBody.Box.PointToMeter(TouchPoint.Position.X, TouchPoint.Position.Y))
        Joint.MaxForce = MaxForce
        Joint.Frequency = Frequency
        Joint.Breakpoint = Breakpoint
        Joint.DampingRatio = DampingRatio
        SelectedBody.Box.World.AddJoint(Joint)
        TouchCollection(e.TouchDevice.Id) = Joint
        e.Handled = True

    End Sub

    Private Sub TouchTrap_Up(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchUp
        If SelectedBody Is Nothing Then Return
        Dim element As FarseerPhysics.Dynamics.Joints.Joint = TouchCollection(e.TouchDevice.Id)
        e.Handled = True
        SelectedBody.Box.World.RemoveJoint(Joint)
        SelectedBody = Nothing
        Joint = Nothing
        TouchCollection.Remove(e.TouchDevice.Id)
    End Sub

    Private Sub TouchTrap_Move(ByVal sender As Object, ByVal e As Windows.Input.TouchEventArgs) Handles Me.TouchMove
        If SelectedBody Is Nothing Then Return
        Dim element As FarseerPhysics.Dynamics.Joints.Joint = TouchCollection(e.TouchDevice.Id)

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(SelectedBody)
        Joint.WorldAnchorB = SelectedBody.Box.PointToMeter(New Point(TouchPoint.Position.X, TouchPoint.Position.Y))
        System.Diagnostics.Debug.WriteLine(Joint.WorldAnchorB.ToString)
    End Sub
End Class
Jul 22, 2011 at 8:23 PM

I haven't been using the surface sdk actually.

It looks like your figuring things out. The problem with lost mouse events is something I had to deal with before. The MouseDrag class has some calls to the CaptureMouse and ReleaseMouseCapture functions. Essentially these keep the mouse events occurring on that UIElement even if the the mouse leaves it. It looks like you took them out for TouchMove. I suspect they don't work the same with the surface sdk, but it must have something equivalent. Something else you can try that helps is to give the TouchDrag object a background in the xaml. When it's transparent mouse events on the background go right though it.

To handle the rotation I was going to suggest you try attaching a FixedAngleJoint to the object along with the FixedMouseJoint and change the target angle based on the touch direction. The problem with that is it will always rotate around its center point instead of the touch point. To overcome that instead of attaching the AngleJoint directly to the object instead create an invisible body at the touch point and attach the AngleJoint to it. Then attach the invisible body to the object with a WeldJoint. This complicates the process quite a bit but I believe it will give you the results you're looking for. I'm not sure exactly what kind of behavior you will get it you touch the same body at two places though.

Jul 24, 2011 at 8:12 AM
Edited Jul 24, 2011 at 8:56 AM

Yes,CaptureTouch(e.TouchDevice) fixed problem 1. I will look into joint-type later, as it should probably be an exposed class-property.

I'm more interested in finding out why multitouch is'nt working. I think there is a problem with SelectedBody. We can have two SelectedBody at the same time. I think we may have to tie the object with the TouchDevice.Id in an array instead of just using a dictionary for the ID's.

TouchTrap_Move should then look up in this array to match id with object,  instead of just seeing if selectedbody is there...

Jul 25, 2011 at 2:44 AM

You're on the right track. The same sort of thing you did with joints has to be done with SelectedBody. I made a structure to keep them together and changed the dictionary to hold the structure instead of just the joint. Try this out and let me know how it works. I don't have the touch sdk installed so I can't actually try this out myself. I may have missed something simple you will have to fix before it works. If we can get this to work I'll add it to the library.

'Copyright (c) 2011, Nicholas Avery
'Licensed under the Microsoft Public License (Ms-PL)
'You may not use this file except in compliance with the License.
'You may obtain a copy of the license at http://xamlphysics.codeplex.com/license

''' <summary>
''' Rewrite for Touch by Jesper Johansen
''' Catches touch events and allows dragging and dropping bodies
''' </summary>
Public Class TouchDrag
    Inherits Canvas

    Private Structure Connection
        Dim Body As PhysicalBody
        Dim Joint As FarseerPhysics.Dynamics.Joints.FixedMouseJoint
    End Structure

    ''' <summary>
    ''' The maximum constraint force that can be exerted to move the candidate body.
    ''' </summary>
    Public Property MaxForce() As Double = 1

    ''' <summary>
    ''' The response speed.
    ''' </summary>
    Public Property Frequency() As Double = 5

    Public Property Breakpoint() As Double = Single.MaxValue

    ''' <summary>
    ''' The damping ratio. 0 = no damping, 1 = critical damping.
    ''' </summary>
    Public Property DampingRatio() As Double = 0.7

    Dim Connections As New Dictionary(Of Integer, Connection)()

    Private Sub TouchDrag_Down(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchDown
        If Connections.ContainsKey(e.TouchDevice.Id) Then Return

        Dim Body = PhysicalBox.GetBody(e.OriginalSource)
        If Body Is Nothing Then Return
        If Body.Body Is Nothing Then Return

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(Body.Box)
        Dim Joint As New FarseerPhysics.Dynamics.Joints.FixedMouseJoint(Body.Body, Body.Box.PointToMeter(TouchPoint.Position))
        Joint.MaxForce = MaxForce
        Joint.Frequency = Frequency
        Joint.Breakpoint = Breakpoint
        Joint.DampingRatio = DampingRatio
        
        Body.Box.World.AddJoint(Joint)

        Dim Connection As Connection
        Connection.Body = Body
        Connection.Joint = Joint
        Connections.Add(e.TouchDevice.Id, Connection)
        
        e.Handled = True
        CaptureTouch(e.TouchDevice)
    End Sub

    Private Sub TouchDrag_Up(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchUp
        If Not Connections.ContainsKey(e.TouchDevice.Id) Then Return

        Dim Connection = Connections(e.TouchDevice.Id)
        Connection.Body.Box.World.RemoveJoint(Connection.Joint)
        
        Connections.Remove(e.TouchDevice.Id)

        e.Handled = True
        ReleaseTouchCapture(e.TouchDevice)
    End Sub

    Private Sub TouchDrag_Move(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchMove
        If Not Connections.ContainsKey(e.TouchDevice.Id) Then Return

        Dim Connection = Connections(e.TouchDevice.Id)

        Dim TouchPoint = e.TouchDevice.GetTouchPoint(Connection.Body.Box)
        Connection.Joint.WorldAnchorB = Connection.Body.Box.PointToMeter(TouchPoint.Position)
    End Sub
End Class

Jul 25, 2011 at 12:31 PM
Edited Jul 25, 2011 at 12:50 PM

Well, I'll be... works beatiful! Well done, Nich!

If two touches are on the same element it just makes two joints... this opens some interesting features.

But the important thing is - works, no exceptions so far.

I just tried to switch FixedMouseJoint with FixedAngleJoint hoping the arguments was the same... Am I correct to understand that FixedAngleJoint fixates the object to the joint, so moving the joint moves the object directly?

Jul 26, 2011 at 9:28 AM

Great

The FixedAngleJoint allows you to give a body a specific angle to maintain relative to the world. It doesn't constrain the x and y cords of the body at all. It's called fixed because the angle is fixed instead of dependent on another attached body like the AngleJoint. Check it out in the docs. http://liserdartsgames.com/LocalResources/XamlPhysics/Joints.html If you want to drag a body around and not allow it to rotate you will have to attach both the FixedMouseJoint and FixedAngleJoint to it.

Now that will work fine but if you start changing the target angle of the FixedAngleJoint you will clearly see that it rotates around the center of the body instead of at the contact point. To overcome that I think the best solution is to crate a small hidden body with no collision detection in the MouseDown event and attach the 2 joints to that body. Then attach the hidden body to the actual on screen body with a WeldJoint.

I installed the surface sdk so I could try this myself but I've been having trouble getting it working.  I'm not sure what's wrong. I can touch the body and I see that the joint is attached to it but the effect it has dragging it around is extremely weak and kind of random. Could you send me a sample project so I can try TouchDrag out myself?

Jul 26, 2011 at 9:39 AM

I have uploaded my project here (very basic). www.stopfx.dk/IO/XamlPhysics Release 0.61 Source.rar . Just run the SurfaceApplication and start the InputSimulator

I've experienced the same on objects that have mass applied.

What I wanted to do was to translate the object in 'Realtime' with the touchdevice, so it doesnt bounce around. If this was, say, an airhockey-pad it would be weird that it doesnt track and follow your finger.

On another note, Gravity... you dont have this variable exposed, do you?

Jul 26, 2011 at 9:40 AM

Just after making that post is occurred to me that I had set the mass of the body very high and that's why it seemed so week. So I've figured it out and no sample project is necessary.

If you can find out/show me how to get the rotation of a contact point I will modify TouchDrag to use that tomorrow. Right now I have to go get some other work done.

Jul 26, 2011 at 9:52 AM

You can try changing the MaxForce Frequency and DampingRatio properties of the TouchDrag class. I don't know what you want to change them too honestly. Probably try increasing MaxForce and decreasing DampingRatio and I have no idea what to do with Frequency. You will just have to do some playing around to find what you want.

Exposing gravity is something else that's been on my ToDo list for a long time, but it's not done right now. It's one line 117 in PhysicalBox.vb if you want to change it.

Jul 26, 2011 at 10:36 AM

Rotation of a touch point:

Up until now we have'nt really done anything that requires the Surface SDK - all is basic Win7 stuff. But getting the direction of a touchpoint is very much Surface, and we shall be careful to make sure it doesnt get locked, per say, to Surface. After they split the Surface SDK in two, and took out all multitouch and put it directly in Win7, they talked about applications would know by themselves which framework to use. I've never seen an example of this. But I suggest duplicating the class for now into SurfaceDrag.VB. It may just work anyway...

Microsoft have extended the basic touch-class from win7 with TouchExtensions class:
http://msdn.microsoft.com/en-us/library/ee957280.aspx

This have a method called GetOrientation:
http://msdn.microsoft.com/en-us/library/microsoft.surface.presentation.input.touchextensions.getorientation.aspx#Y570

But this requires a hookup to InputEventArgs instead of TouchEventArgs so it should probably be a function of it's own, that just returns angle as a double, IF Surface is recognized... TouchMove function should then be called from that with the angle as a parameter.

I'm not really sure if it really is necessary though. Multitouch rotation is more or less considered a two-finger operation anyway, to keep the abstract to the physical world.

Jul 27, 2011 at 2:18 AM

I thought you wanted to use the touch rotation but if not I'll just let it be. I don't want to make Xaml Physics to be specific to surface.

I made the changes to TouchDrag to stop rotation of a body while it is being dragged. It can be turned off with the StopRotaion property. And then I added it to the repository. The PhysicalBox class now has a gravity property you can use to turn off or change the force and direction of gravity. It still defaults to the same.

Aug 1, 2011 at 11:33 AM
Edited Aug 1, 2011 at 1:06 PM

Hi again

I've tried to modify TouchDrag a bit more. What I want to achieve is having the UI Element (ie. the ellipse, rectangle etc.) move with the touch (no joints), without losing it's physical capabilities. It feels weird that objects move away from a touchpoint, which usually is perceived as a static. I can get close by setting MaxForce and Frequency to 10 and Damping to 1, but it is not as responsive, as I would like.

I can move the object with RenderTransform, but that (obviously) offsets the PhysicalBody. So I reckon instead I have to update the UI Elements Canvas.Left and Canvas.Top property. How do I get the parent of the PhysicalBox and set those properties in VB?Can you see any obstacles in doing this?

On another note - If I have a rectangle (static) and an ellipse (ignore gravity) and slowly bounce the ellipse into the rectangle, it does'nt bounce back. If this ellipse is outside TouchDrag and you only have other objects to bounce it with, it is impossible to get it to move away from the rectangle...

Aug 2, 2011 at 3:04 AM

Directly changing the position of bodies isn't something the Farseer Physics engine supports. This is something that comes up every once in a while in the discussions. The problem is your asking how to create an unstoppable force. It's not usually an issue unless it interacts with an unmovable (static) object. When that happens you'll probably see things jump around a little. But to do it your best but is probably to switch from a FixedMouseJoint to a FixedRevoltJoint like this.

'Copyright (c) 2011, Nicholas Avery
'Licensed under the Microsoft Public License (Ms-PL)
'You may not use this file except in compliance with the License.
'You may obtain a copy of the license at http://xamlphysics.codeplex.com/license

''' <summary>
''' Catches touch events and allows dragging and dropping bodies
''' </summary>
''' <remarks>
''' Rewrite for Touch by Jesper Johansen
''' </remarks>
Public Class TouchDrag
    Inherits Canvas

    Private Structure Connection
        Dim Body As PhysicalBody
        Dim MouseJoint As FarseerPhysics.Dynamics.Joints.FixedRevoluteJoint
        Dim AngleJoint As FarseerPhysics.Dynamics.Joints.FixedAngleJoint
    End Structure

    ''' <summary>
    ''' The maximum constraint force that can be exerted to move the candidate body.
    ''' </summary>
    Public Property MaxForce() As Double = 100

    ''' <summary>
    ''' The response speed.
    ''' </summary>
    Public Property Frequency() As Double = 5

    ''' <summary>
    ''' The damping ratio. 0 = no damping, 1 = critical damping.
    ''' </summary>
    Public Property DampingRatio() As Double = 0.7

    Public Property LinearBreakpoint() As Double = Single.MaxValue

    Public Property TorqueBreakpoint() As Double = Single.MaxValue

    ''' <summary>
    ''' If true, a FixedAngleJoint will be created to stop rotation of the touched body
    ''' </summary>
    Public Property StopRotaion() As Boolean = True


    Dim Connections As New Dictionary(Of Integer, Connection)()

    Private Sub TouchDrag_Down(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchDown
        If Connections.ContainsKey(e.TouchDevice.Id) Then Return

        Dim Body = PhysicalBox.GetBody(e.OriginalSource)
        If Body Is Nothing Then Return
        If Body.Body Is Nothing Then Return

        Dim TouchPoint = Body.Box.PointToMeter(e.TouchDevice.GetTouchPoint(Body.Box).Position)

        Dim MouseJoint As New FarseerPhysics.Dynamics.Joints.FixedRevoluteJoint(Body.Body, Body.Body.GetLocalPoint(TouchPoint), TouchPoint)
        MouseJoint.Breakpoint = LinearBreakpoint
        Body.Box.World.AddJoint(MouseJoint)
        
        Dim AngleJoint As New FarseerPhysics.Dynamics.Joints.FixedAngleJoint(Body.Body)
        AngleJoint.TargetAngle = Body.Body.Rotation
        AngleJoint.Breakpoint = TorqueBreakpoint
        If StopRotaion Then
            Body.Box.World.AddJoint(AngleJoint)
        End If

        Dim Connection As Connection
        Connection.Body = Body
        Connection.MouseJoint = MouseJoint
        Connection.AngleJoint = AngleJoint
        Connections.Add(e.TouchDevice.Id, Connection)
        
        e.Handled = True
        CaptureTouch(e.TouchDevice)
    End Sub

    Private Sub TouchDrag_Up(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchUp
        If Not Connections.ContainsKey(e.TouchDevice.Id) Then Return

        Dim Connection = Connections(e.TouchDevice.Id)
        Connections.Remove(e.TouchDevice.Id)

        Connection.Body.Box.World.RemoveJoint(Connection.MouseJoint)
        Connection.Body.Box.World.RemoveJoint(Connection.AngleJoint)
        
        e.Handled = True
        ReleaseTouchCapture(e.TouchDevice)
    End Sub

    Private Sub TouchDrag_Move(sender As Object, e As Windows.Input.TouchEventArgs) Handles Me.TouchMove
        If Not Connections.ContainsKey(e.TouchDevice.Id) Then Return
        
        Dim Connection = Connections(e.TouchDevice.Id)
        
        Dim TouchPoint = e.TouchDevice.GetTouchPoint(Connection.Body.Box)
        Connection.MouseJoint.WorldAnchorB = Connection.Body.Box.PointToMeter(TouchPoint.Position)
    End Sub

End Class

For this to work the sleep optimization must be turned off. Otherwise the revolt joint will stop moving the body if/when it stops rotating. It's easy enough to do. Just insert this before you start the simulation.

FarseerPhysics.Settings.AllowSleep = False

This isn't always the best solution. Try it out and see what it's like.

 

What you are experiencing with ellipses not bouncing is because of it's speed. Any collision below a given speed will not bounce as an optimization. It's called VelocityThreshold and is also in the Settings class. It's in meters per second and defaults to 1. Xaml Physics defaults to interpreting 350 pixels as 1 meter but you can change that with the PixelsInAMeter property of PhysicalBox. So either decrease PixelsInAMeter or VelocityThreshold but there will still always be a point that collisions do not bounce. You just have to find what is right for what you're doing.





Aug 2, 2011 at 10:55 AM

Thank you - works perfectly! Much better experience and response with the Revolute Joint for touch.

Oct 13, 2011 at 7:56 PM

I've tried both versions of the TouchDrag class - the one in the source tree, and the one described above. I do see that the version using FixedRevoluteJoint tracks more closely to the finger, but has the side effect of not imparting any momentum to the corresponding body. I've found that this means you can't really 'fling' an object via touch, as you can with the version using FixedMouseJoint. I'm also seeing some cases where using FixedRevoluteJoint will let a tracked body to punch through a static one - in the sample with the four static walls, I can sometimes drag one of the objects outside the box.

So for now, the smoother tracking and fling behavior of the mouse joint implementation seem to be preferable to the tighter tracking of the revolute joint one.

Oct 14, 2011 at 8:42 AM

Yes, I also prefer FixedMouseJoint and then adjusting damping etc. as you can see other discussions about here. It is a more believable touch-experience. Regarding your issues with intersecting geometry, there is a thread called 'intersections' here, which helped me out - it's basically just a setting.