Now It’s Time To Go, Numbers

There’s only one place for me to begin with writing articles about coding. The most fundamental parts of the JEOZ Engine are GoNumbers, GoVectors, and GoColors. Games require smooth movement, and building these objects into the core of the JEOZ Engine makes that effortless and automatic.

Simply put, you move from one point to another at X Percent each frame of animation. Instead of a constant motion which looks robotic, it starts very fast and slides to a stop. If you apply this to Arrow Key (WASD) inputs, it will smooth out the motion to feel more like a joystick. When the player switches from moving straight forward, then moving to the side, there will be a moment of diagonal motion in between.

And while I know that FPS gamers want instant mouse feedback, using the Slide() function with a very high Percent is still a good idea. Fast enough to not impact gameplay, but enough to stabilize jitter. I realize I’m from the older N64 generation of gamers, but I find that 60 FPS with a high DPI mouse causes the screen’s motion to be overstimulating. Maybe if I became a gamer again I’d get used to it, but still, gaming is becoming a “spectator sport”, and if you want a bigger audience, the show has to be comfortable to watch. You wouldn’t show most of a football game from helmet cameras.

Anyway, the simplest version of this concept has fields I call Now and Go. You set GoNumber.Go to the target value at any time. Then call Slide(0.##) once every GameLoop to move the Now value towards Go, at ## percent of the distance. The Slide() Function takes a decimal above 0 and less than 1, and uses that combined with the current TimeStep. Using 0 or 1 would either make it do nothing, or move Now to Go instantly. SlideClamp(0.##) will limit the Percentage to 0-1 for you.

Then you read the GoNumber.Now field any time you want to Get the GoNumber’s current state. The GoNumber.Value Property can be used to Get the Now value and Set the Go value respectively, but that might result in some confusion. You usually do that anyway, because Now is always moving, and you Set the Go value to tell it where to move. But sometimes you want to change the Now value to push a number away from it’s destination, so it will automatically Slide() back.

    Public Sub Slide(ByVal Percentage As Single,
                     Optional ByVal Smooth As Single = 0.5)
        '// Store the difference of motion
        Change = Go - Now
        '// Smoothly adjust Velocity towards Change
        Velocity += ((Change - Velocity) * Smooth) * Time.Step
        '// Move Now towards Go based on Velocity
        '// Use Change instead of Velocity take out this extra smoothing
        Now += ((Velocity) * Percentage) * Time.Step
    End Sub

Note that I’m adding C-style comments after VB’s apostrophe comments to make it more readable for C# users. Also, “ByVal” and “ByRef” are VB’s way of using Pointers. The parameter is passed “By Value” if unspecified, and specifying “By Reference” turns the Parameter into a Pointer.

Recently I added an extra Smooth parameter, so the Velocity doesn’t jump too suddenly. This also takes a 0-1 decimal, although anything less than 0.4 causes strange glitches in motion.

I also recently added the Glide() function, which uses a Cosine curve to move the number. The drawback is that you have to set the Now and Go just once each time you move the number, and you can only change the Velocity and Acceleration once it’s moving. The Slide() function on the other hand allows for the Go value to constantly change, and Now will always follow it appropriately.

    Public Sub GlideStart(_Now As Single, _Go As Single, _Velocity As Single,
                          Optional _Acceleration As Single = 0)
        Now = _Now : Start = _Now : Go = _Go : Difference = Go - Now
        Velocity = _Velocity : Acceleration = _Acceleration

        Direction = Math.Sign(Difference)
        If Difference = 0 Then Difference = 1
        InverseDifference = 1 / Difference
        Change = 0
    End Sub
    Public Sub GlideAdjust(_Go As Single, _Velocity As Single,
                           Optional _Acceleration As Single = 0)
        GlideStart(Now, _Go, _Velocity, _Acceleration)
    End Sub
    Public Sub Glide()
        Velocity += Acceleration * Time.Step
        Change += Velocity * Time.Step
        '// Divide via multiplying the inverse
        Percent = ABS(Change * InverseDifference)
        '// Cosine starts at +1 and goes down to -1, but we want 0 to 1
        '// So flip the polarity, halve it, and bump it up above zero
        Now = Start + (((-Cose(Percent * 180) * 0.5) + 0.5) * Difference)

        Difference = ABS(Go - Now)
        '// If Difference < 0.01 Then Velocity = 0
        Velocity *= -(Difference > 0.01)
        '// If Difference < 0.1 Then Velocity *= 0.8
        Velocity = (Velocity * -(Difference >= 0.1)) +
                   (Velocity * (-(Difference < 0.1) * 0.8))

        '// If Difference < 0.01 Then Acceleration = 0
        Acceleration *= -(Difference < 0.01)
   End Sub

The GoVector object contains GoNumbers X, Y, and Z as Fields, as well as OpenTK.Vector3 Now and Go Properties, so you can Get and Set them as Vector3 objects.

You can find the full source code on my PasteBin page at pastebin.com/u/MyGameIsJeo, or use the icon at the top right of this blog.

Leave a Reply