In this episode, we continue with the floaters.  Among some strange new things that we'll have to deal with concerning the 
floaters is how to set the properties of the floater using the editor.  Other things like using the floater arraylist and file 
I/O should be common knowledge by now.

First, we will only be concerning ourselves with getting multiple floaters.  This should be simple by now, but I'll show it 
again (as always).
Declaration:

    Dim Floaters As ArrayList
    'Holds all of the floaters for this level.
Initialization - replace this:
        Floater = New LevFloater(New Rectangle(420, 400, FLOATERSIZE, FLOATERSIZE), 5, 5, 16, 16, PeriodicDesignation.CosineFxn, PeriodicDesignation.SineFxn)
        'Information about the floater.  The width and height are all determined by the floatersize constant.
With this:
        Floaters = New ArrayList(10)
        Floaters.Add(New LevFloater(New Rectangle(420, 400, FLOATERSIZE, FLOATERSIZE), 5, 5, 16, 16, PeriodicDesignation.CosineFxn, PeriodicDesignation.SineFxn))
        Floaters.Add(New LevFloater(New Rectangle(550, 200, FLOATERSIZE, FLOATERSIZE), 5, 5, 16, 16, PeriodicDesignation.SineFxn, PeriodicDesignation.CosineFxn))
        'Information about the floater.  The width and height are all determined by the floatersize constant.
To draw these floaters, replace the existing code for drawing one floater with:
        For Each Floater In Floaters
            GFX.DrawImage(FloatBmp, Floater.Loc.X, Floater.Loc.Y)
            'Draw the floater to the display.  There's only one frame, so no selection involved.
        Next
And to support multiple floater movement, we use a For Loop, as shown below. Notice that I am not using a For Each loop. This is because we are changing the value of the floater. Since Floater is a structure, not a class reference, we have to assign the Floater to a floater variable, modify the floater variable, and put it back in the arraylist. This is similar to what we did with the coins (when they were collected, they were set to empty rectangles). Also, notice that the FloatTick does not go into this loop. It only needs to be incremented once:
        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
            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
            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
And we also have to check if any of the floaters have touched the player, so in the collision checks, change the existing code to this:
            For Each Floater In Floaters
                If Floater.Loc.IntersectsWith(PlayerLoc) Then
                    IsGoner = True
                    'The player has touched the floater.  Lose a life.
                    PlayerVeloc = SBARINITIALVELOCITY
                End If

            Next
Now that that is done, you should have two decently functioning floaters on the form.
The next task would be to add floaters to the form using the editor. However, we are facing a problem because we have to create a new floater. Our previous endeavors required us to only create a rectangle at runtime, but now we have to find some way of setting the radius, frequency, and the periodic function to use. Clearly, we can't do this with just the mouse (aside from having loads of non-obvious shortcuts). We'll need to make a dialog form. So, press Ctrl+Shift+A (that's File->Add New Item) and add a new form to the project. Name it whatever you want, but mine is named FloaterEd. Now, let's add some NumericUpDown controls. Add one for the radispeed X (1), one for radispeed Y (2), one for frequency X (3), and one for frequency Y (4). To do the enumeration, we should add two comboboxes or listboxes. You can add whichever one you want, but I'm going to use comboboxes since they are so small. Now, for the numericupdown controls, we will set the maximum size for the radispeed. The radispeed is the radius times the frequency (divided by the frequencydivider of course), the radius should be no larger than 400 (half the width of the form), and, let's say the frequency shouldn't be any larger than 40, equal to 5120 / 128 (which is quite fast - you can try it - but ultimately the speed depends on the period of the periodic function that we are using). So, the maximum value for the radispeed should be 5120 * 400 which is about 204800. The chances of us using a number that high are quite low, but eventually we'll come back to make this easier. Now, we set the first two numericupdowns to have a maximum of 204800 and a minimum of -204800. The second two are the frequency functions and, as mentioned before, the maximum is 5120 (divided by the frequencydivider). The minimum would be 0 for even and odd periodic functions like cosine and sine, but we may have periodic functions that are neither even nor odd, so we'll set the minimum to -5120 for now. My comboboxes have their dropdownstyles both set to dropdownlist. We can also add some labels to this form so that we're not guessing when we edit the floater properties. Now, we need to add an OK button to the form. In this OK button, we will collect our values, convert them to integers and return a levfloater structure with everything set except for the rectangle. But, before we do that, we need to get the comboboxes working. We can use the Enum.GetNames to get an array containing the names of the elements in the enumeration. This will be handy because we will not have to update this form when we add more periodic functions.
    Private Sub FloaterEd_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.ComboBox1.Items.AddRange(System.Enum.GetNames(PeriodicDesignation.Stable.GetType()))
        'Adds periodic functions to combobox1.
        Me.ComboBox2.Items.AddRange(System.Enum.GetNames(PeriodicDesignation.Stable.GetType()))
        'Also to combobox2.
    End Sub
Nothing to it, right? Now, for the OK button. We need to allow the game form to interact with the floater on this form. So, first, we'll declare a private LevFloater variable and make a Public ReadOnly Property so that we can return this LevFloater variable to the other form.
    Private Flot As LevFloater
    'The floater that will be returned by this prompt form.
    Public ReadOnly Property Floater() As LevFloater
        Get
            Return Flot
        End Get
    End Property
Then, we need to add the coding for the OK button.
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim HFxn As PeriodicDesignation = CType(ComboBox1.SelectedIndex, PeriodicDesignation)
        Dim VFxn As PeriodicDesignation = CType(ComboBox2.SelectedIndex, PeriodicDesignation)
        'Get the periodic functions to use.
        Dim RSpdX As Integer = Convert.ToInt32(Me.NumericUpDown1.Value)
        Dim RSpdY As Integer = Convert.ToInt32(Me.NumericUpDown2.Value)
        Dim FreqX As Integer = Convert.ToInt32(Me.NumericUpDown3.Value)
        Dim FreqY As Integer = Convert.ToInt32(Me.NumericUpDown4.Value)
        'Get the radispeeds and frequencies.


        Flot = New LevFloater(Rectangle.Empty, RSpdX, RSpdY, FreqX, FreqY, HFxn, VFxn)
        'Filled in all properties except for the rectangle.
        Me.Close()
        'Close the form when OK is clicked, like all dialogs do.
    End Sub
And, we are finished with this form. Now, we return to the main game form, where we will begin adding the editor support and interface for floaters. First, we go to the KeyDown event so we can assign a key that denotes that we are using Floaters. "F" would be a logical choice.
        ElseIf e.KeyCode = Keys.F Then
            If Not IsMouseDown Then
                MDObject = "F"c
            End If
And, now we go to the MouseUp event, where the object that we have just drawn will be added to the appropriate form collection. Here, we'll have to show the form so that we can get the final six properties set on the floater. This has to be done before we assign the rectangle to the floater. Remember that we initialized the floater to have an empty rectangle, so we have to overwrite this rectangle to complete the floater.
            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(Mu.X, Mu.Y, FLOATERSIZE, FLOATERSIZE)
                '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.
So, the floater will not be moving in the same circle or whatever shape assigned to it. The shape will be shifted somehow based on the value of FloatTick. But, it should work.
Now, to put these floaters into the file. This might seem easy:
            'Floaters are written to file.
            BW.Write(Floaters.Count)
            For Each Floater In Floaters
                BW.Write(Floater.Loc.Left)
                BW.Write(Floater.Loc.Top)
                BW.Write(Floater.RadispeedX)
                BW.Write(Floater.RadispeedY)
                BW.Write(Floater.FrequencyX)
                BW.Write(Floater.FrequencyY)
                BW.Write(Floater.FunctionHorizontal)
                BW.Write(Floater.FunctionVertical)
            Next
And that's all there is to it, right? Wrong. Why? We remembered not to save the right and bottom of the floater. Keep in mind that the floaters are moving the whole while, so, if you were to save this one file over and over again, you'd probably find the floaters mysteriously drift over to the right side of the screen. So, how do we fix this so that our floaters don't drift upon each save and load? A. Disable the floater movement block. B. Disable the floattick increment. C. Disable the timer enabling event. Disabling the timer enabling event would stop the floaters from moving, but it would also stop any new drawings from being made. Disabling the floattick increment would not stop the movement of the floaters. The correct answer is A., to disable the floater movement in the CharacterMovement sub. Now, how do we disable the entire For loop? Well, since we do not want the floaters to move while we are in the editor (the TESTversion), we will simply wrap the entire block in #If TESTversion = 0 Then ... #End If Note that this is the same problem that occurs if you collect a coin before you save the level. You'd see one or more coins have magically teleported to the upper left corner of the screen, because, despite them being collected, their coordinates remain in the coins arraylist. Wrapping the coin collection block with the same #If compilation block would prevent coins from being collected while the testversion is running. You could also remove the coins from the arraylist, but I'm not going to do that. Set up some floaters and save them to file.
Now, to load the floaters back from file, we just add this.
        Floaters = New ArrayList(BR.ReadInt32())
        For LV = 1 To Floaters.Capacity
            Floaters.Add(New LevFloater(New Rectangle(BR.ReadInt32(), BR.ReadInt32(), FLOATERSIZE, FLOATERSIZE), _
            BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(), BR.ReadInt32(), _
            CType(BR.ReadInt32(), PeriodicDesignation), CType(BR.ReadInt32(), PeriodicDesignation)))
        Next
        Floaters.Capacity = 20
Notice, we have to use CType to convert the enumeration value back into an Integer. Don't forget to remove this from the load procedure:
        Floaters = New ArrayList(10)
        Floaters.Add(New LevFloater(New Rectangle(420, 400, FLOATERSIZE, FLOATERSIZE), 5, 5, 16, 16, PeriodicDesignation.CosineFxn, PeriodicDesignation.SineFxn))
        Floaters.Add(New LevFloater(New Rectangle(550, 200, FLOATERSIZE, FLOATERSIZE), 5, 5, 16, 16, PeriodicDesignation.SineFxn, PeriodicDesignation.CosineFxn))
Switch the TESTversion #constant back to 0 so you can see the floaters move. That concludes this section on floaters. Next, we'll do a little bit of scenario handling for the jumping.