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 |
Private Function Nearest8(ByVal Number As Integer) As Integer Return (Number + 4) And (Not &O7) End Function |
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. |
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 |
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)) |
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 |
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 |
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 |
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 |