Welcome again.  In this episode, we will be dealing with functions.  First on our agenda is how to make our editor a
little more refined.  Up until now, the editor makes it hard to make nice-looking maps.  So, to remedy this problem,
we will make all of our points follow a snap-to-grid, which means that all of our points will snap to the closest of
some certain values.
In this demonstration, we will snap all of our points to the closest multiple of 8.
So, sounds easy right?  All we need to do is take all of the points that we get in the MouseUp event and round them
to the closest 8.  This will be made easier by making a function that will round any integer we pass it to the
nearest 8.

Rounding to the nearest 8 *sounds* easy: 0->0, 1->0, 2->0, 3->0, 4->8, 5->8, 6->8, 7->8
And there are a lot of ways to do it.  Since this functionality is only for the editor, we really don't *need* it to
be as fast as possible, although, it wouldn't hurt for it to be fast.
    Private Function RoundTo8(ByVal Number As Integer) As Integer
        Return 8 * Convert.ToInt32(Math.Round(Number / 8, 0))
    End Function
Surely, this is a valid solution as well, and probably the first one that comes to mind if you are used to it. My version would be below, however , but it would barely make a difference in which function you use, since it will only be called four times.
    Private Function Nearest8(ByVal Number As Integer) As Integer
        Return (Number + 4) And (Not &O7)
    End Function
Now, we have to apply this function. We could just round the points in the MouseUp event so only our final result is on the grid. We can also round the points in the Artwork sub so that our selection rectangle snaps to the grid as well. First, let's do the MouseUp snapping. In the MouseUp event, we can (actually we could have long ago) have the rectangle that represents where the new object will go. The 'Placed' Rectangle variable can do this for us. So, before we even enter the Select Case block, we can set up the Placed Rectangle. Placed = Rectangle.FromLTRB(Math.Min(InitialPt.X, Mu.X) + ScreenLeft, Math.Min(InitialPt.Y, Mu.Y) + ScreenTop, Math.Max(InitialPt.X, Mu.X) + ScreenLeft, Math.Max(InitialPt.Y, Mu.Y) + ScreenTop) This is how it would have been before. Now:
        Placed = Rectangle.FromLTRB(Nearest8(Math.Min(InitialPt.X, Mu.X) + ScreenLeft), Nearest8(Math.Min(InitialPt.Y, Mu.Y) + ScreenTop), _
                                    Nearest8(Math.Max(InitialPt.X, Mu.X) + ScreenLeft), Nearest8(Math.Max(InitialPt.Y, Mu.Y) + ScreenTop))
        'Our completed selection rectangle.
And we no longer have to assign Placed right before we use it for the Platforms, Walls, and Lava. Coins and Floaters are another matter, but you can leave those out of the rounding operation.
    Private Sub PFMain_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
        Dim Placed As Rectangle
        'This is the rectangle that we have drawn.
        Dim Mu As Point = New Point(e.X, e.Y)
        'Convert the mouseeventargs's .X and .Y into a Point structure.
        IsMouseDown = False

        Placed = Rectangle.FromLTRB(Nearest8(Math.Min(InitialPt.X, Mu.X) + ScreenLeft), Nearest8(Math.Min(InitialPt.Y, Mu.Y) + ScreenTop), _
                                    Nearest8(Math.Max(InitialPt.X, Mu.X) + ScreenLeft), Nearest8(Math.Max(InitialPt.Y, Mu.Y) + ScreenTop))
        'Our completed selection rectangle.

        Select Case MDObject
            Case "P"c
                'For platforms.
                Platforms.Insert(0, Placed)
                'Add a platform.
            Case "W"c
                'For walls.
                Walls.Insert(0, Placed)
                'Add a wall.
            Case "L"c
                'For lava.
                Lavas.Insert(0, Placed)
                'Add a wall.
            Case "C"c
                Coins.Insert(0, New Rectangle(Nearest8(Mu.X + ScreenLeft), Nearest8(Mu.Y + ScreenTop), COINSIZE, COINSIZE))
                'Place a coin at the point where the mouse was released.
            Case "F"c
                Clock.Enabled = False
                'Lighten the processing load while we set up our floater.
                Dim Fm As FloaterEd = New FloaterEd
                Fm.ShowDialog()
                'After the showdialog, the floater's final six properties will be set.
                'But, the rectangle will be empty.
                Dim Fltr As LevFloater = Fm.Floater
                'Copy the floater to our variable.
                Fltr.Loc = New Rectangle(Nearest8(Mu.X + ScreenLeft), Nearest8(Mu.Y + ScreenTop), FLOATERSIZE, FLOATERSIZE)
                'For the floater...
                'Set the rectangle.  The size is fixed, so we just make the rectangle like we did for the coin.
                Floaters.Insert(0, Fltr)
                'And this final floater will be added.
                'The movement of the floater after it is added to the form is not the exact movement that it will have
                'when it is loaded from file, because the value of FloatTick is not always 0 when the floater is created, and its
                'movement depends on the value of floattick with the periodic function.
                Clock.Enabled = True
                'Continue game.
        End Select
    End Sub
And then, for the Artwork subroutine and drawing the selection rectangle.
            Outline = Rectangle.FromLTRB(Math.Min(Nearest8(InitialPt.X + ScreenLeft) - ScreenLeft, Nearest8(Curse.X + ScreenLeft) - ScreenLeft), _
                                         Math.Min(Nearest8(InitialPt.Y + ScreenTop) - ScreenTop, Nearest8(Curse.Y + ScreenTop) - ScreenTop), _
                                         Math.Max(Nearest8(InitialPt.X + ScreenLeft) - ScreenLeft, Nearest8(Curse.X + ScreenLeft) - ScreenLeft), _
                                         Math.Max(Nearest8(InitialPt.Y + ScreenTop) - ScreenTop, Nearest8(Curse.Y + ScreenTop) - ScreenTop))
Now, the snapping process is complete.
If you happened to be following the periodic section, you'll find my formulas for squares, triangles, and etc. These same formulas can be ported over to .NET as well, with a few modifications, of course.
    Private Function Fmd(ByVal Nume As Single, ByVal Denom As Single) As Single
        Dim ItE As Double = Math.IEEERemainder(Nume, Denom)
        'Finally figured out how this function works.
        If ItE < 0 Then
            ItE = Denom + ItE
        End If
        Return Convert.ToSingle(ItE)
    End Function
And then, there's the actual functions.
    Private Function Fmd(ByVal Nume As Single, ByVal Denom As Single) As Single
        Dim ItE As Double = Math.IEEERemainder(Nume, Denom)
        'Finally figured out how this IEEERemainder function works.
        If ItE < 0 Then
            ItE = Denom - ItE
        End If
    End Function
    Private Function TrglDif(ByVal N As Single) As Single   'Squarewave used for generating the trianglewave.
        Dim Res As Single = Fmd(N, 2)  'Fmd now takes a numerator and a denominator.
        If Res >= 0 AndAlso Res < 1 Then
            Return 1
        Else
            Return -1
        End If
    End Function
    Private Function HxgnDif(ByVal N As Single) As Single
        Dim Res As Single = Fmd(N, 4)
        If Res >= 0 AndAlso Res < 1 Then
            Return 2
        ElseIf Res >= 1 AndAlso Res < 2 Then
            Return 0
        ElseIf Res >= 2 AndAlso Res < 3 Then
            Return -2
        Else
            Return 0
        End If
    End Function
    Private Function TrpzDif(ByVal N As Single) As Single
        Dim Res As Single = Fmd(N, 3)
        If Res >= 0 AndAlso Res < 1 Then
            Return 0
        ElseIf Res >= 1 AndAlso Res < 2 Then
            Return 2
        Else
            Return -2
        End If
    End Function
    Private Function SclnDif(ByVal N As Single) As Single
        Dim Res As Single = Fmd(N, 3)
        If Res >= 0 AndAlso Res < 1 Then
            Return 2
        Else
            Return -1
        End If
    End Function
Our enumeration will also have to be changed.
Public Enum PeriodicDesignation
    Stable = 0  'Denotes that the object will not move in this direction.
    CosineFxn   'Moves using the cosine function.
    SineFxn     'Moves using the sine function.
    Triangle
    Hexagon
    Trapezoid
    Scalene
End Enum
And integrating these functions with our existing floaters.
        Dim LP As Integer
        For LP = 0 To Floaters.Count - 1
            Floater = DirectCast(Floaters(LP), LevFloater)
            'Since we are changing properties of the floater, and since floater is a structure, we have to reassign the
            'newly modified floater back to the array.

            Select Case Floater.FunctionHorizontal
                'Looking at the function that we have designated, we choose the proper periodic function for setting to dX and dY.
            Case PeriodicDesignation.CosineFxn
                    dX = Convert.ToInt32(Floater.RadispeedX * Math.Cos(Convert.ToDouble(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.SineFxn
                    dX = Convert.ToInt32(Floater.RadispeedX * Math.Sin(Convert.ToDouble(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Stable
                    dX = 0
                Case PeriodicDesignation.Triangle
                    dX = Convert.ToInt32(Floater.RadispeedX * TrglDif(Convert.ToSingle(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Hexagon
                    dX = Convert.ToInt32(Floater.RadispeedX * HxgnDif(Convert.ToSingle(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Trapezoid
                    dX = Convert.ToInt32(Floater.RadispeedX * TrpzDif(Convert.ToSingle(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Scalene
                    dX = Convert.ToInt32(Floater.RadispeedX * SclnDif(Convert.ToSingle(FloatTick) * Floater.FrequencyX / Me.FREQUENCYDIVIDER))
            End Select
            Select Case Floater.FunctionVertical
                'Looking at the function that we have designated, we choose the proper periodic function for setting to dX and dY.
            Case PeriodicDesignation.CosineFxn
                    dY = Convert.ToInt32(Floater.RadispeedY * Math.Cos(Convert.ToDouble(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.SineFxn
                    dY = Convert.ToInt32(Floater.RadispeedY * Math.Sin(Convert.ToDouble(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Stable
                    dY = 0
                Case PeriodicDesignation.Triangle
                    dY = Convert.ToInt32(Floater.RadispeedY * TrglDif(Convert.ToSingle(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Hexagon
                    dY = Convert.ToInt32(Floater.RadispeedY * HxgnDif(Convert.ToSingle(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Trapezoid
                    dY = Convert.ToInt32(Floater.RadispeedY * TrpzDif(Convert.ToSingle(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
                Case PeriodicDesignation.Scalene
                    dY = Convert.ToInt32(Floater.RadispeedY * SclnDif(Convert.ToSingle(FloatTick) * Floater.FrequencyY / Me.FREQUENCYDIVIDER))
            End Select

            Floater.Offset(dX, dY)
            'Move the floater using our offset subroutine.
            Floaters(LP) = Floater
            'Return the floater that we've modified to the array.
        Next