Scrolling starfeld with parallax

Previous topic - Next topic

PeeJay

Nothing earth shattering here, but just a little side project I have started working on, and this code might be useful to someone ..... feel free to use and abuse :)

Code (glbasic) Select
SETSCREEN 640,480,1
LIMITFPS 60

TYPE star
x
y
z
ENDTYPE
GLOBAL stars[] AS star

SetupStars()

WHILE TRUE

UpdateStars()
DrawStars()

WEND

END

FUNCTION SetupStars:

LOCAL loop,loop2,num
FOR loop=1 TO 4
IF loop=1 THEN num=6
IF loop=2 THEN num=15
IF loop=3 THEN num=40
IF loop=4 THEN num=100
FOR loop2=1 TO num
LOCAL st AS star
st.x=RND(640)
st.y=RND(480)
st.z=loop
DIMPUSH stars[],st
NEXT
NEXT

ENDFUNCTION

FUNCTION UpdateStars:

FOREACH st IN stars[]
st.y=st.y+(1/st.z)
IF st.y>480
st.x=RND(640)
st.y=st.y-481
ENDIF
NEXT

ENDFUNCTION

FUNCTION DrawStars:

BLACKSCREEN
FOREACH st IN stars[]
LOCAL col=255-(st.z*50)
SETPIXEL st.x,st.y,RGB(col,col,col)
NEXT
SHOWSCREEN

ENDFUNCTION
www.peejays-remakes.co.uk
For games, remakes, and GL Basic Tutorials
Artificial Intelligence is no match for Natural Stupidity

AndyH

Excellent stuff.

Here's a fake 3D starfield using the distance from the origin (centre of screen) to work out the speed of each star at any given point and a cheap parallax effect using a division modifier.  I used to use this method in old 68000 days on the ST/Amiga using bitwise rotates as they were cheap and no need for SIN/COS tables.  In GLB I've used multiply and divisions as speed is not the problem anymore :)

Code (glbasic) Select
// --------------------------------- //
// Project: StarField
// Start: Sunday, January 13, 2008
// IDE Version: 5.129


SETSCREEN 640,480,1
LIMITFPS 60

TYPE star
    x
    y
ENDTYPE
GLOBAL stars[] AS star

GLOBAL xorigin = 320
GLOBAL yorigin = 240


SetupStars()
BLACKSCREEN

WHILE TRUE

    UpdateStars()
    DrawStars()
    SHOWSCREEN
   
WEND

END

FUNCTION SetupStars:

    LOCAL loop
    FOR loop=1 TO 200
LOCAL st AS star
        st.x=RND(32000) +50
        IF (RND(1)) THEN st.x = -st.x
        st.y=RND(24000) + 50
        IF (RND(1)) THEN st.y = -st.y
       
   DIMPUSH stars[],st
    NEXT

ENDFUNCTION

FUNCTION UpdateStars:
LOCAL speed = 150, t = 0

    FOREACH st IN stars[]
st.x = st.x + (st.x / speed)
st.y = st.y + (st.y / speed)

IF MOD ( t, BOUNDS( stars[], 0 )/10 )=0 THEN DEC speed, 10
INC t,1

        IF st.y>22000 OR st.y < -22000 OR st.x>30000 OR st.x < -30000
       st.y=RND(2000)+100
       IF (RND(1)) THEN st.y = -st.y
       st.x=RND(2000) +100
       IF (RND(1)) THEN st.x = -st.x
        ENDIF
    NEXT

ENDFUNCTION

FUNCTION DrawStars:

     FOREACH st IN stars[]
        LOCAL col = ( ( ABS( st.x ) + ABS( st.y ) ) / 56000 ) * 255
        SETPIXEL xorigin+ st.x / 100, yorigin+ st.y / 100 ,RGB(col,col,col)
    NEXT

ENDFUNCTION
There's other ways to do this with calculation of the Z-axis,  but I've always like this method for a quick and easy starfield/

StuC

Or how about a rotating / moving starfield   ( yea uses sin/cos but this day and age shouldnt be a problem)

Use cursor keys  left right to rotate
up down to speed up slow down

Code (glbasic) Select
SETSCREEN 640,480,0

GLOBAL NumOfStars = 300   // how many stars on screen

TYPE star
    x
    y
    ang
    rad
    speed
ENDTYPE

GLOBAL stars[] AS star

GLOBAL xorigin = 320
GLOBAL yorigin = 240

GLOBAL rotationspeed = 1
GLOBAL MAXSpeed = 0
SetupStars()
BLACKSCREEN

WHILE TRUE

IF KEY(203)
rotationspeed=rotationspeed-0.1
ENDIF

IF KEY(205)
rotationspeed=rotationspeed+0.1
ENDIF

IF KEY(208)
MAXSpeed = MAXSpeed - 0.01
IF MAXSpeed <= 0  // limit so the stars dont invert
MAXSpeed = 0
ENDIF
ENDIF

IF KEY(200)
MAXSpeed = MAXSpeed + 0.001
ENDIF

    UpdateStars()
    SHOWSCREEN
   
WEND

END

FUNCTION SetupStars:

    LOCAL loop
    FOR loop=1 TO NumOfStars
        LOCAL st AS star
        st.ang = RND(360) + 1
        st.rad = RND(300) + 1
st.speed = (RND(10) + 5)/10
        DIMPUSH stars[],st
    NEXT

ENDFUNCTION

FUNCTION UpdateStars:
LOCAL col

    FOREACH st IN stars[]
   
    st.ang = st.ang - rotationspeed // turn the angle
    st.rad = st.rad + st.speed      // update distance
    st.speed = st.speed + MAXSpeed  // update speed
        st.x = xorigin +(SIN(st.ang) * st.rad)
        st.y = yorigin + (COS(st.ang) * st.rad)
       
        IF st.rad > 400   // offscreen ? - reset star
        st.ang = RND(360) + 1
        st.rad = RND(50)      
st.speed = (RND(10) + 5)/10  
        ENDIF

col = MOD( (st.rad / 350) * 255, 255)  // make colour brighter

        SETPIXEL  st.x , st.y  ,RGB(col,col,col)


    NEXT

ENDFUNCTION

Quentin


AndyH


Kitty Hello

For PocketPC/GP2X there's a qmath.gbas in the Samples/Common folder. It defines QSIN and QSQR and stuff, which are much faster.

PeeJay

Okay, as the starfield coding seems to have been evolving :)  (and because I fancied porting some Blitz code over), I've done a 3D starfield myself. Movement is currently randomized, but it will move in the x and y planes, and will rotate on the z axis, plus there is motion blur on the stars and variable brightness depending on their distance.

I wonder what the next offering will bring? :D

Code (glbasic) Select
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//                                                                      //
// Project: GLStarfield                                                 //
//                                                                      //
// (C)opyright PeeJay 2008                    www.peejays-remakes.co.uk //
//                                                                      //
// A 3D Starfield with movement and motion blur - the full monty! :o)   //
//                                                                      //
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//

SETSCREEN 640,480,0
LIMITFPS 60

GLOBAL ax,ay,az,axvel,ayvel,azvel,axacc,ayacc,azacc,cx,sx,cy,sy,cz,sz

TYPE star
    x
    y
    z
    zvel
    prevx
    prevy
ENDTYPE
GLOBAL stars[] AS star

SetupStars()

WHILE TRUE

axacc=axacc+((RND(12)-6)/10000)
ayacc=ayacc+((RND(12)-6)/10000)
azacc=azacc+((RND(12)-6)/10000)

axvel=axvel+axacc ; ayvel=ayvel+ayacc ; azvel=azvel+azacc

axacc=axacc*0.99 ; ayacc=ayacc*0.99 ; azacc=azacc*0.99
axvel=axvel*0.99 ; ayvel=ayvel*0.99 ; azvel=azvel*0.99

ax=(ax+axvel)*0.99 ; ay=(ay+ayvel)*0.99 ; az=(az+azvel)*0.99

cx=COS(ax) ; sx=SIN(ax) ; cy=COS(ay) ; sy=SIN(ay) ; cz=COS(az) ; sz=SIN(az)

    DoStars()
   
WEND

END

FUNCTION SetupStars:

    LOCAL loop
   
    FOR loop=1 TO 300
    LOCAL st AS star
    st.x=RND(800)-400
    st.y=RND(800)-400
    st.z=100+RND(900)
    st.zvel=RND(5)+0.5
    st.prevx=-1000
    st.prevy=0
    DIMPUSH stars[],st
    NEXT

ENDFUNCTION

FUNCTION DoStars:

LOCAL tx,tz,ty,tx2,x,y,xd,yd,bl,br

BLACKSCREEN

FOREACH st IN stars[]
IF st.prevx<0 OR st.prevx>640 OR st.prevy<0 OR st.prevy>480 OR st.z<1
    st.x=RND(800)-400
    st.y=RND(800)-400
    st.z=100+RND(900)
    st.zvel=RND(5)+0.5
    st.prevx=-1000
    st.prevy=0
ENDIF

st.z=st.z-st.zvel

tx=(st.x*cy)+(st.z*sy) ; tz=(st.z*cy)-(st.x*sy) ; ty=(st.y*cx)+(tz*sx)
tz=(tz*cx)-(st.y*sx) ; tx2=(tx*cz)+(ty*sz) ; ty=(ty*cz)-(tx*sz) ; tx=tx2

x=((tx/tz)*100)*3+320 ; y=((ty/tz)*100)*3+240

IF st.prevx=-1000
xd=0 ; yd=0 ; bl=1
ELSE
xd=x-st.prevx ; yd=y-st.prevy ; bl=SQR((xd*xd)+(yd*yd))
ENDIF

br=255-((st.z*255)/1000) ; br=(br*st.zvel)/6

IF bl>1 AND bl<50
DRAWLINE x,y,st.prevx,st.prevy,RGB(br,br,br)
ELSE
SETPIXEL x,y,RGB(br,br,br)
ENDIF

st.prevx=x ; st.prevy=y

NEXT

SHOWSCREEN

ENDFUNCTION
www.peejays-remakes.co.uk
For games, remakes, and GL Basic Tutorials
Artificial Intelligence is no match for Natural Stupidity

Schranz0r

I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

Kitty Hello


Minion

OK, not looked at the others, but as this is a star field thread, thought I`d post mine too ...

Code (glbasic) Select
// --------------------------------- //
// Project: Starfield
// Start: Thursday, January 24, 2008
// IDE Version: 5.146


TYPE star
   ang
   pos
ENDTYPE

GLOBAL str AS star

LOCAL strz[] AS star


FOR m=1 TO 100
str.ang=RND(360)
str.pos=RND(200)
DIMPUSH strz[],str
NEXT

SETSCREEN 640,480,1

WHILE(0=0)

ALPHAMODE 1
show_stars(strz[],0.25,-0.1)

ALPHAMODE -0.255
DRAWRECT 0,0,1280,1024,RGB(32,32,32)
USEASBMP

SHOWSCREEN

WEND

// ------------------------------------------------------------- //
// ---  SHOW_STARS  ---
// ------------------------------------------------------------- //
FUNCTION show_stars: stz[] AS star,spd,rot
// These values are defined LOCAL:
//
LOCAL spd
LOCAL rot
flag=0
scx=320
scy=240
FOREACH str IN stz[]


a=str.ang
p=str.pos



FOR q=1 TO 4 STEP 1
qq=q*vv
i=((100.0)/p)*100
xx=(SIN(a)*i)*q
yy=(COS(a)*i)*q

ik=i/2
IF ik>255 THEN ik=255

SETPIXEL scx+xx+1,scy+yy,RGB(ik,ik,ik)
SETPIXEL scx+xx-1,scy+yy,RGB(ik,ik,ik)
SETPIXEL scx+xx,scy+yy-1,RGB(ik,ik,ik)
SETPIXEL scx+xx,scy+yy+1,RGB(ik,ik,ik)
ik=ik*2
IF ik>255 THEN ik=255
SETPIXEL scx+xx,scy+yy,RGB(0,ik,ik)
a=a+90
IF a>360 THEN a=a-360


NEXT



p=p-spd
a=a-rot
IF a>360 THEN a=a-360

IF p>200 THEN p=1
IF p<1 THEN p=200
str.pos=p
str.ang=a

NEXT


ENDFUNCTION // SHOW_STARS

phil

#10
Hi i needed help to understand how to store data in Arrays, I didnt understand the examples above fully so i set about writing my own parallax star field... It has really helped me understand and is written out very simply, uses 2 arrays, no types and could be reproduced even shorter but of course that would make it more complicated for a noob... like me. It looks great and is just 23 lines of code  =D

Code (glbasic) Select

//Simple 3 layer Parallax stars by Phil Lewis-- (fully comented-->)

SETSCREEN 640, 480, 1
//--(Setup DIM storage & Random x y coordinate generator)--
DIM x[1000]                                                                          // I want to store 1000 x coordinates (0-999)
DIM y[1000]                                                                          // I want to store 1000 y coordinates (0-999)
FOR loop=0 TO 1000 -1                                                                // loop the commands 999 times in between FOR and NEXT
    x[loop]=RND(640)                                                                 // adding random values to y (using loop above)
    y[loop]=RND(480)                                                                 // adding random values to y (using loop above)
NEXT                                                                                 // go back to FOR (until loop is exhausted)

//--(Draw (Back) pixels at the x and y coordinates)--
WHILE TRUE                                                                           // Repeat the commands between WHILE and WEND
  FOR loop2 = 0 TO 100 - 1                                                           // loop the commands 99 times in between FOR and NEXT
   y[loop2]= y[loop2] + 0.3                                                          // 0.3 pixel per frame is added to each y coordinate
    SETPIXEL x[loop2], y[loop2], RGB(100,100,100)                                    // draw pixels @ x & y coordinates
     IF y[loop2] > 480 THEN y[loop2] =y[loop2] - 480                                 // y is set to top of screen when it reaches the bottom
NEXT                                                                                 // Go back to FOR

//------------------(middle)-------------------------
FOR loop3 = 200 TO 270 - 1                                                           // loop the commands 99 times in between FOR and NEXT
  y[loop3]= y[loop3] + 0.5                                                           // 0.3 pixel per frame is added to each y coordinate
   SETPIXEL x[loop3], y[loop3], RGB(150,150,150)                                     // draw pixels @ x & y coordinates
    IF y[loop3] > 480 THEN y[loop3] =y[loop3] - 480                                  // y is set to top of screen when it reaches the bottom
NEXT                                                                                 // Go back to FOR

//------------------(Front)--------------------------
FOR loop4 = 300 TO 330 - 1                                                           // loop the commands 99 times in between FOR and NEXT
  y[loop4]= y[loop4] + 1                                                             // 0.3 pixel per frame is added to each y coordinate
   SETPIXEL x[loop4], y[loop4], RGB(255,255,255)                                     // draw pixels @ x & y coordinates
    IF y[loop4] > 480 THEN y[loop4] =y[loop4] - 480                                  // y is set to top of screen when it reaches the bottom
NEXT                                                                                 // Go back to FOR

SHOWSCREEN                                                                           // Print everything so far to the screen
WEND                                                                                 // Go back to WHILE

MrTAToad

That would be easier if you used TYPE's to record the colour and position - that way, you could (theoretically) have up to 255 layers.