soulshined soulshined - 4 years ago 66 Question

VB/C# Shape follow cursor but constrain bounds

I'm having a difficult time emulating an 'eyeball' effect. I have an

(as in PowerPack shape) and can constrain the movement to a specific x,y. However, I need a fresh eyes to help me out, I think I've been looking at it too long to make any sense of it.

The goal:

Emulate an eyeball movement experience by following the cursor position.


Cursor position is of
type, ergo, it's relative to the form.
The object/shape is relative to a
so MousePosition 10,10 will translate to EyePupil position 10,10 because the location is based on it's parent

Here's a synopsis:


Dim MousePosition As Drawing.Point

.....Handles MyBase.Load

Dim ctrl As System.Windows.Forms.Control
For Each ctrl In Me.Controls
AddHandler ctrl.MouseMove, AddressOf OnMouseMoveHandler

Dim canvas As New ShapeContainer
canvas.Parent = Me.EyeIcon

Me.EyePupilShape.Parent = canvas

Handling the events:


MousePosition = Me.PointToClient(Cursor.Position)
Debug.Print("Mouse position : X = " & MousePosition.X & ", " & MousePosition.Y)

Me.EyePupilShape.Location = New Drawing.Point(Clamp(MousePosition.X, 32, 50), Clamp(MousePosition.Y, 31, 50))

Where Clamp is just a custom version of MathHelper.clamp and the min/max values are where the 'pupil' of the eye should be constrained to within it's parent element

This works as in it confines the pupil to a specific x,y bounds

However, it doesn't 'follow' the cursor per sey. For example, if the cursor is on the bottom left, it doesn't recognize that, it's just based on x,y values, that's were I need help with what I have so far. For what it's worth I've gotten most of my info from MSDN

Answer Source

You need to take the angle to the mouse cursor into account, then calculate position on a unit circle based on that angle, and scale by radius of your "pupil movement area", adjusting for mouse position being inside the eye/pupil.

I wrote a sample in VB.NET, posted on Github.

Calculations are within the Eyeball.Pupil.Update(Point mouse) function, which receives the mouse coordinates translated using PointToClient() function, as in your case. Here's the code:

    Public Sub Update(ByVal mouse As Point)
        'Calculate angle to mouse position'
        Dim distanceVector = New PointF(mouse.X - _center.X, mouse.Y - _center.Y)
        Dim angleToMouse = Math.Atan2(distanceVector.Y, distanceVector.X)

        'If the mouse is within the movement radius, restrict movement'
        Dim absDistanceVector As PointF = distanceVector
        If absDistanceVector.X < 0 Then absDistanceVector.X *= -1
        If absDistanceVector.Y < 0 Then absDistanceVector.Y *= -1

        'Calculate scale'
        Dim scale = New PointF(Math.Min(absDistanceVector.X, _movementRadius.X),
                               Math.Min(absDistanceVector.Y, _movementRadius.Y))

        'Adjust X and Y of the pupil based on scaled vector to mouse cursor, offset by pupil origin'
        X = CType(Math.Cos(angleToMouse), Single) * scale.X + _center.X - BoundingBox.Width / 2
        Y = CType(Math.Sin(angleToMouse), Single) * scale.Y + _center.Y - BoundingBox.Height / 2

    End Sub 

Ignore the closing single-quotes at the end of the comments - I added these to properly colorize the code in this post.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download