Android Example 3D Interactive Starfield using only the Core library

Hey guys!!

I took this HTML5 example and adapted it to B4A.

I hope the code is self-explanatory, if not, I'll be here to help.
Once again I'm using panels, but you can use whatever objects you want to represent the stars. I recommend, as always, LibGDX.
B4X:
#Region  Project Attributes

    #ApplicationLabel: 3D Starfield Example
    #VersionCode: 1
    #VersionName:
    'SupportedOrientations possible values: unspecified, landscape or portrait.
    #SupportedOrientations: Landscape
    #CanInstallToExternalStorage: False
#End Region

#Region  Activity Attributes
    #FullScreen: True
    #IncludeTitle: False
#End Region

Sub Process_Globals
    Dim Main_Engine As Timer
End Sub


Sub Globals
    'Starfield
        Dim number_of_stars = 64 As Float
        Dim star_speed = 0.4 As Float

        Dim max_depth = 32 As Float
        Dim star_x(number_of_stars) As Float
        Dim star_y(number_of_stars) As Float
        Dim star_z(number_of_stars) As Float
        Dim smin = -25 As Int
        Dim smax =  26 As Int

        Dim star(number_of_stars) As Panel

        Dim centerX = 50%x As Float
        Dim centerY = 50%y As Float

        Private TouchScreen As Panel
End Sub


Sub Activity_Create(FirstTime As Boolean)
    Activity.LoadLayout("Test")

    For i = 0 To (number_of_stars - 1)
        'Initialize 3D Coordinates
            star_x(i) = Rnd(smin, smax)
            star_y(i) = Rnd(smin, smax)
            star_z(i) = Rnd(1, max_depth)

        'Initialize Panels
            star(i).Initialize("Star")
            Activity.AddView(star(i), 0, 0, 0, 0)
    Next

    Main_Engine.Initialize("Main_Engine", 16)
    Main_Engine.Enabled = True

    TouchScreen.Left = 0%x
    TouchScreen.Top = 0%x
    TouchScreen.Width = 100%x
    TouchScreen.Height = 100%y
    TouchScreen.BringToFront

End Sub


Sub Activity_Resume
    Main_Engine.Enabled = True
End Sub


Sub Activity_Pause (UserClosed As Boolean)
    Main_Engine.Enabled = False
End Sub


Sub Main_Engine_Tick
       Starfield(10, centerX, centerY, star_speed)
End Sub


Sub Starfield(star_size As Float, x_center As Float, y_center As Float, speed As Float)
       For i = 0 To (number_of_stars - 1)

              'Moves the star in the z-axis
                  star_z(i)= star_z(i) - speed

              'Resets the star position once it's offscreen
                  If star_z(i) <= 0 Then
                         star_x(i) = Rnd(smin, smax)
                         star_y(i) = Rnd(smin, smax)
                         star_z(i) = max_depth
                  End If

              'Black magic happens here, can't explain this part (3D to 2D conversion), I only know it works
                  Dim k  = 128 / star_z(i) As Float
                  Dim px = star_x(i) * k + x_center As Float
                  Dim py = star_y(i) * k + y_center As Float

              'Display the star as long as its 2D position is on screen
                  If px >= 0%x AND px <= 100%x AND py >= 0%x AND py <= 100%y Then
                     Dim size = (1 - (star_z(i) / 32.0)) * star_size As Float
                     Dim shade = (1 - (star_z(i) / 32.0)) * 255 As Float

                     'Displaying a single star:
                            'The Aplha level is given by how distant in the z-axis the star is
                                   star(i).Color = Colors.ARGB(shade, 0, Rnd(128,192), Rnd(192,255))
                            'Set the star size according to the z-axis distance
                                   star(i).Width = size
                                   star(i).Height = size
                            'Makes px and py the center of the star
                                   star(i).Left = px - (star(i).Width / 2)
                                   star(i).Top = py - (star(i).Height / 2)


                    '=====================================================================================================
                    'LibGDX "Sub LG_Render" code example:
                    '    Batch.DrawRegion2(star(i), px - Half_of_the_star_size, py - Half_of_the_star_size, size, size)
                    '=====================================================================================================

                  End If
       Next
End Sub


Sub TouchScreen_Touch (Action As Int, X As Float, Y As Float)
    Select Action
            Case Activity.ACTION_DOWN
                centerX = X
                centerY = Y
                star_speed = star_speed * 2

            Case Activity.ACTION_MOVE
                centerX = X
                centerY = Y
 
            Case Activity.ACTION_UP
                star_speed = star_speed / 2
 
    End Select
End Sub
 

Attachments

  • Starfield Example.zip
    7.7 KB · Views: 701
Last edited:

Informatix

Expert
Licensed User
Longtime User
I didn't examine closely the generated source and I cannot say whether it's really safe to use %x and %y in Globals. But to be sure, I avoid doing it and prefer to use these units only in subs. When the activity has been created and is ready to be used (Activity_Create event), the activity dimensions are not likely to change.
 

wonder

Expert
Licensed User
Longtime User
B4X:
              'Black magic happens here, can't explain this part (3D to 2D conversion), I only know it works
                  Dim k  = 128 / star_z(i) As Float
                  Dim px = star_x(i) * k + x_center As Float
                  Dim py = star_y(i) * k + y_center As Float

Any math wizard out there who wants to help me understand this part?

HAPPY NEW YEAR!!!!!!!!!!!!!!!!!!!!!!!!!
 

sorex

Expert
Licensed User
Longtime User
k is pseudo depth multiplier.

it's used as z based offset multiplier multiplied to x & y so you get the depth look.
(the bigger k gets (positive or negative) the farther from the center it goes thus close to you)

you can also do it with only sin/cos math and a z counter then it's radial based.
 

wonder

Expert
Licensed User
Longtime User
Thanks for the explanation!! But where does the 128 comes from? It's on the original example but I couldn't figure it out.
 

sorex

Expert
Licensed User
Longtime User
I bet that source comes from an old 256x256 pixel byte based starfield example.

that's why you have 128 there, it's half of a byte thus the center value which you divide with the distance so the offset goes from aprox -127 to +127.

add that to the center value and it's nicely positioned inside the visual area of the 256x256 field.
 
Cookies are required to use this site. You must accept them to continue using the site. Learn more…