Android Example 3D Interactive Starfield using only the Core library

wonder

Expert
Licensed User
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

Last edited:

Informatix

Expert
Licensed 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
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? :D

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

sorex

Expert
Licensed 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
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.
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
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.
 
Top