Author Topic: Some base code for Ludum Dare  (Read 2491 times)

Offline Wampus

  • Prof. Inline
  • *****
  • Posts: 1004
    • View Profile
Some base code for Ludum Dare
« on: 2012-Aug-25 »
Below is some base code I'm using for Ludum Dare. Nothing new here really. I'm including it so I don't have to worry about coding screen resizing, loading maps, loading TextureMap sprites, dealing with polyvector commands and frame skipping. This code should take care of all that so I can get on with making a terrible 2D game. :)

Globals: -

Code: GLBasic [Select]
// Plaform and resolution settings
GLOBAL zoom# = 1.0              // proportional zoom for different screens. 1 is 800x480
GLOBAL plats% = 0               // for platform type - just PC for first release
GLOBAL xres#, yres#             // actual screen resolution goes here
GLOBAL midxres#, midyres#       // middle of screen
GLOBAL xvir#, yvir#             // virtual screen size
GLOBAL xborder#, yborder#       // border, if needed

GLOBAL xmap#, ymap#                     // map size
GLOBAL xtile#, ytile#           // tile size
GLOBAL map%[]                           // the map array itself
GLOBAL pmap%[]                          // the path-finding map

TYPE texturemap
        x#              // x pos on sheet
        y#              // y pos on sheet
        w#              // width
        h#              // height
ENDTYPE

GLOBAL sprites#[] AS texturemap         // Texture map for sprites
GLOBAL tiles#[] AS texturemap           // Texture map for tiles

GLOBAL TMsprites%               // where is sprite texture map held?
GLOBAL TMtiles%                 // where is tile texture held?

// Poly handling

GLOBAL xoff1#, yoff1#   // rotation offsets
GLOBAL xoff2#, yoff2#   // rotation offsets
GLOBAL xoff3#, yoff3#   // rotation offsets
GLOBAL xoff4#, yoff4#   // rotation offsets

GLOBAL SF_curd# = 16.66666666666667     // current d frame
GLOBAL throttle% = FALSE        // should we limit the speed the app is going?
GLOBAL SF_fullflag% = FALSE             // has 60FPS ever been reached as a guess?

// Not yet confirmed but useful
GLOBAL SF_timer#, SF_oldtimer#                  // timers for measuring speed of app
GLOBAL SF_baseFPS#
GLOBAL SF_framenum# = 60        // number of frames in loop count
GLOBAL SF_frames#[]             // array for storing previous FPS times in
DIM SF_frames[SF_framenum]              // 60 frames worth of timings to measure
GLOBAL SF_loopframe% = BOUNDS(SF_frames[], 0)           // if this reached then loop to 0
GLOBAL SF_curframe% = 0         // current frame working on
GLOBAL SF_countframe% = 0       // how many frames have we counted so far. Doesn't go over SF_loopframe
GLOBAL SF_flagloop% = FALSE     // is true once SF_loopframe has been done once
GLOBAL SF_sumframes# = 0        // summary of frame timings
GLOBAL SF_m# = 0                        // running measure
GLOBAL SF_mflag% = FALSE        // has a measure adjustment been made in the last 60 frames?
GLOBAL loopdo# = 0                      // number of loops to go through

// The Guessing game
GLOBAL SF_guess% = 0            // If there is a guess this will be it
GLOBAL guessnum% = 3    // how many guesses / virtual seconds in a row have to be the same for SF_curd adjustment
GLOBAL curguess% = 0    // current guess
GLOBAL gstore#[]                // array for guess counts
DIM gstore[guessnum]    // arrays

// Controls

GLOBAL press# = 0               // how long has touch / button been pressed
GLOBAL mx#, my#, ma#, mb#       // mouse button

Base Code: -

Code: GLBasic [Select]
FUNCTION LoadMap: name$

LOCAL sbyte%
LOCAL xnow%, ynow%
LOCAL solid% = 10       // from this tile number upwards the way is unpassable

OPENFILE(1, name$, 1)

FILESEEK 1, 8, 0


READWORD 1, sbyte       // bad integer type for direct read so put into sbyte first
xmap = sbyte            // x dimension of map
READWORD 1, sbyte
ymap = sbyte            // y dimension of map
READBYTE 1, sbyte
xtile = sbyte           // x size for tile
READBYTE 1, sbyte
ytile = sbyte           // y size for tile

DIM map[xmap][ymap]             // dimension the array
DIM     pmap[xmap][ymap]        // dimension the pathfinding array

FOR i = 0 TO (xmap*ymap)-1

        READBYTE 1, sbyte

        map[xnow][ynow] = sbyte

        IF sbyte >= solid       // if tile is solid

                pmap[xnow][ynow] = 0    // can't go here

        ELSE

                pmap[xnow][ynow] = 1    // is walkable

        ENDIF

        INC xnow

        IF xnow = xmap

                xnow = 0
                INC ynow

        ENDIF

NEXT

CLOSEFILE 1

ENDFUNCTION



FUNCTION LoadSprites: filename$, sprsheet%

LOCAL sprnum%   // number of sprites successfully added
LOCAL tempspr# AS texturemap
LOCAL chr%      // for reading back character
LOCAL sprname$  // sprite name
LOCAL num$      // to convert to number

// load new texture map into a sprite sheet
LOADSPRITE filename$+".png", sprsheet

IF OPENFILE(1, filename$+".txt", 1) = FALSE
        PRINT "Damned odd!! Texture Packer file not found", 0, 0
        PRINT filename$+".txt", 0, 10
        PRINT GETCURRENTDIR$(), 0, 20
        SHOWSCREEN
        MOUSEWAIT
ELSE    // load sprites

        WHILE ENDOFFILE(1) = FALSE

                // read sprite name
                chr = 0
                sprname$ = ""
                WHILE chr <> 44

                        READUBYTE 1, chr

                        IF chr <> 44 THEN INC sprname$, CHR$(chr)

                WEND

                // move beyond space
                FILESEEK 1, 1, 1

                // read x position
                chr = 0
                num$ = ""
                WHILE chr <> 44

                        READUBYTE 1, chr

                        IF chr <> 44 THEN INC num$, CHR$(chr)

                WEND

                tempspr.x = num$

                // move beyond space
                FILESEEK 1, 1, 1

                // read y position
                chr = 0
                num$ = ""
                WHILE chr <> 44

                        READUBYTE 1, chr

                        IF chr <> 44 THEN INC num$, CHR$(chr)

                WEND

                tempspr.y = num$

                // move beyond space
                FILESEEK 1, 1, 1

                // read width
                chr = 0
                num$ = ""
                WHILE chr <> 44

                        READUBYTE 1, chr

                        IF chr <> 44 THEN INC num$, CHR$(chr)

                WEND

                tempspr.w = num$

                // move beyond space
                FILESEEK 1, 1, 1

                // read height
                chr = 0
                num$ = ""
                WHILE chr <> 44

                        READUBYTE 1, chr

                        IF chr <> 44 THEN INC num$, CHR$(chr)

                WEND

                tempspr.h = num$

                FILESEEK 1, 12, 1       // move on 14 bytes

                // add new sprite to array

                DIMPUSH sprites[], tempspr

                sprname$=LEFT$(sprname$, LEN(sprname$)-4)

                // assign an index number to new sprite
                SpriteAdd(sprname$, sprnum)

                // Testing
//              DRAWSPRITE sprsheet, 0, 0
//              PRINT "File position: "+FILEPOSITION (1), 0, 0
//              PRINT "Sprite name: "+sprname$, 0, 10
//              PRINT "Sprite number: "+sprnum, 0, 20
//              PRINT "Sprite x: " +tempspr.x, 0, 30
//              PRINT "Sprite y: " +tempspr.x, 0, 40
//              PRINT "Sprite width: " +tempspr.w, 0, 50
//              PRINT "Sprite height: " +tempspr.h, 0, 60
//              SHOWSCREEN
//              MOUSEWAIT
                // End of testing

                INC sprnum

        WEND    // end of end of file check

ENDIF   // end of opening file

RETURN sprnum

ENDFUNCTION



FUNCTION SpriteAdd: idname$, index

SELECT idname$

        CASE "bigsprite"

                bigone = index

        DEFAULT

                // do nout

ENDSELECT

ENDFUNCTION




///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Poly Roto Zoom Anim                                                                                              //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

FUNCTION PolySprite: num%, xpos#, ypos#, angle# = 0, hotpoint% = 7, xscale# = 1.0, yscale# = 1.0, hflip% = FALSE, vflip% = FALSE, pcolour% = 16777215

LOCAL patx#, paty#, patxx#, patyy#      // texture co-ords
LOCAL pltx#, plty#, plbx#, plby#, prbx#, prby#, prtx#, prty#    // position co-ordinates
LOCAL porwidth#, porheight#, pwidth#, pheight#  // position fixing
LOCAL porcentx#, porcenty#, pcentx#, pcenty#    // for centering
LOCAL pminx#, pminy#, pmaxx#, pmaxy#    // for rotation
LOCAL midx#, midy#      // for mid points
LOCAL xoff1#, yoff1#    // rotation offsets
LOCAL xoff2#, yoff2#    // rotation offsets
LOCAL xoff3#, yoff3#    // rotation offsets
LOCAL xoff4#, yoff4#    // rotation offsets

// if horizontal flip
IF hflip = FALSE
        patx = sprites[num].x
        patxx = sprites[num].x+sprites[num].w
ELSE
        patx = sprites[num].x+sprites[num].w
        patxx = sprites[num].x
ENDIF

// if vertical flip
IF vflip = FALSE
        paty = sprites[num].y
        patyy = sprites[num].y+sprites[num].h
ELSE
        paty = sprites[num].y+sprites[num].h
        patyy = sprites[num].y
ENDIF

// calculate proportions for sprite
porwidth = sprites[num].w * zoom
porheight = sprites[num].h * zoom
pwidth = porwidth * xscale
pheight = porheight * yscale
porcentx = porwidth / 2
porcenty = porheight / 2
pcentx = pwidth / 2
pcenty = pheight / 2

// depending on hotpoint, reposition the final sprite
SELECT hotpoint

        CASE 7  // top left
                pltx = xpos * zoom
                plty = ypos * zoom

        CASE 8  // top
                pltx = xpos * zoom - pcentx
                plty = ypos * zoom

        CASE 9  // top right
                pltx = xpos * zoom - pwidth
                plty = ypos * zoom

        CASE 4  // left
                pltx = xpos * zoom
                plty = ypos * zoom - pcenty

        CASE 5  // center
                pltx = xpos * zoom - pcentx
                plty = ypos * zoom - pcenty

        CASE 6  // right
                pltx = xpos * zoom - pwidth
                plty = ypos * zoom - pcenty

        CASE 1  // bottom left
                pltx = xpos * zoom
                plty = ypos * zoom - pheight

        CASE 2  // bottom
                pltx = xpos * zoom - pcentx
                plty = ypos * zoom - pheight

        CASE 3  // bottom right
                pltx = xpos * zoom - pwidth
                plty = ypos * zoom - pheight

        DEFAULT // assume center, 5
                pltx = xpos * zoom - pcentx
                plty = ypos * zoom - pcenty

ENDSELECT


// now add other variables needed for sprite placement
plbx = pltx
plby = plty + pheight
prtx = pltx + pwidth
prty = plty
prbx = prtx
prby = plby

// if rotation is required then rotate the sprite co-ordinates
IF angle <> 0

        midx = (pltx+prbx)/2
        midy = (plty+prby)/2

        xoff1 =  ( (COS(angle)*(pltx-midx)) - (SIN(angle)*(plty-midy)) ) + porcentx * xscale
        yoff1 =  ( (SIN(angle)*(pltx-midx)) + (COS(angle)*(plty-midy)) ) + porcenty * yscale

        xoff2 =  ( (COS(angle)*(plbx-midx)) - (SIN(angle)*(plby-midy)) ) + porcentx * xscale
        yoff2 =  ( (SIN(angle)*(plbx-midx)) + (COS(angle)*(plby-midy)) ) - porcenty * yscale

        xoff3 =  ( (COS(angle)*(prtx-midx)) - (SIN(angle)*(prty-midy)) ) - porcentx * xscale
        yoff3 =  ( (SIN(angle)*(prtx-midx)) + (COS(angle)*(prty-midy)) ) + porcenty * yscale

        xoff4 =  ( (COS(angle)*(prbx-midx)) - (SIN(angle)*(prby-midy)) ) - porcentx * xscale
        yoff4 =  ( (SIN(angle)*(prbx-midx)) + (COS(angle)*(prby-midy)) ) - porcenty * yscale

        INC pltx, xoff1
        INC plty, yoff1

        INC plbx, xoff2
        INC plby, yoff2

        INC prtx, xoff3
        INC prty, yoff3

        INC prbx, xoff4
        INC prby, yoff4

ENDIF


// Draw final polyvector
POLYVECTOR pltx, plty, patx, paty, pcolour
POLYVECTOR plbx, plby, patx, patyy, pcolour
POLYVECTOR prbx, prby, patxx, patyy, pcolour

POLYVECTOR prbx, prby, patxx, patyy, pcolour
POLYVECTOR prtx, prty, patxx, paty, pcolour
POLYVECTOR pltx, plty, patx, paty, pcolour

ENDFUNCTION




FUNCTION Initialise:

LOCAL plat$ = PLATFORMINFO$("")

IF plat$="ANDROID"
        plats = 3       // Android
        GETDESKTOPSIZE xres, yres
        AUTOPAUSE TRUE
        ALLOWESCAPE FALSE
        SETORIENTATION 0
ELSEIF plat$="MACOSX"
        plats = 1       // Mac
        GETSCREENSIZE xres, yres
        SYSTEMPOINTER TRUE
        AUTOPAUSE TRUE
        ALLOWESCAPE TRUE
ELSEIF plat$="LINUX"
        plats = 2       // Linux
        GETSCREENSIZE xres, yres
        SYSTEMPOINTER TRUE
        AUTOPAUSE TRUE
        ALLOWESCAPE TRUE
ELSEIF plat$="WIN32"
        plats = 0       // The game is running on a PC computer
        GETSCREENSIZE xres, yres
        SYSTEMPOINTER TRUE
        AUTOPAUSE TRUE
        ALLOWESCAPE TRUE
ELSE
        plats = 2       // Treat as Pre bug on WebOS 1.4.5
ENDIF

// cal midpoint
midxres = xres/2
midyres = yres/2


// Aspect ratio always 5:3 - my virtual screen is 800 x 480
IF xres/yres <= 1.666666666666667       // if x res is not too small for 5/3 aspect ratio

        zoom = xres/800         // now we have our zoom factor

        yborder = (yres - 480*zoom) / 2
        xborder = 0
        xvir = xres
        yvir = yres - yborder*2

ELSE    // more letterbox than 800x480

        zoom = yres/480

        xborder = (xres - 800*zoom) / 2
        yborder = 0
        yvir = yres
        xvir = xres - xborder*2

ENDIF

ENDFUNCTION




FUNCTION OldFPS:

   STATIC OldTimeReport$,FPSDat,TimeReport$,FPSd,nada
   IF nada < 60
        INC nada
        FPSd = -1
        OldTimeReport$=TimeReport$; FPSDat=FPSDat+1;
        TimeReport$=PLATFORMINFO$("TIME")
        IF OldTimeReport$<>TimeReport$; FPSDat=0; ENDIF
   ELSE
         OldTimeReport$=TimeReport$; FPSDat=FPSDat+1;
         TimeReport$=PLATFORMINFO$("TIME")
         IF OldTimeReport$<>TimeReport$; FPSd=FPSDat ; FPSDat=0; ENDIF
   ENDIF

RETURN FPSd

ENDFUNCTION




FUNCTION FSMeasureTimerEnd:

SF_oldtimer = SF_timer

SF_timer = GETTIMERALL()                // measure the timer at the end of this loop

SF_baseFPS = SF_timer - SF_oldtimer             // work out how long it took for one complete loop

INC SF_m, SF_curd - SF_baseFPS

IF SF_flagloop = FALSE          // if no loop yet

        INC SF_sumframes, SF_baseFPS
        SF_frames[SF_curframe] = SF_baseFPS                     // add the current time into the frames list but don't minus anything

ELSE    // we have looped

        DEC SF_sumframes, SF_frames[SF_curframe]        // remove old value from total before adding new
        INC SF_sumframes, SF_baseFPS            // add new value
        SF_frames[SF_curframe] = SF_baseFPS

ENDIF

INC SF_curframe, 1              // move on one frame

// See if we have reached one full measurement
IF SF_countframe < SF_loopframe

        INC SF_countframe

        IF SF_countframe = SF_loopframe         // we have now made a complete loop
                SF_flagloop = TRUE      // so flag it
        ENDIF

ENDIF

//Now, calculate the number of frames that need to be caught up with

loopdo = 0      // always assume nothing to be done next frame, just to be safe

IF SF_m < -SF_curd      // if our measure is really low

        LOCAL re_m#             // remainder of measure after nasties removed

        SF_mflag = TRUE // we have used the measure recalc
        re_m = FMOD(-SF_m, SF_curd)     // find the remainder when divided
        loopdo = (-SF_m - re_m) / SF_curd

        INC SF_m, loopdo*SF_curd

        INC loopdo              // add one more action loop, the normal action loop

ELSEIF SF_m > SF_curd           // Oops. We running THAT fast, and subsquently potentially messing up frameskip calcs

        SF_m = 0        // just reset to zero to be safe
        loopdo = 1      // normal frames

ELSE

        loopdo = 1              // Normal frames

ENDIF   // End of measures taken on measure


// Do checks if we've reached end of the loopframe
IF SF_curframe = SF_loopframe

        SF_curframe = 0         // have we reached the end? Then loop
        FSGuess()       // run guess checks
        IF SF_mflag = FALSE     // no skips this loop
                SF_m = 0        // reset measure (for re-balancing)
        ENDIF

        SF_mflag = FALSE

ENDIF

ENDFUNCTION


// Guess the average FPS
FUNCTION FSGuess: reset% = FALSE

LOCAL guess%            // this guess
LOCAL oldguess%         // any guess to check
LOCAL sameflag% = TRUE

IF reset = TRUE // we reset the guess values and start again. Else

        curguess = 0
        REDIM gstore[0]

ELSE    // we are actually meant to check

        SELECT SF_sumframes

//              CASE 1933 TO 2067                                       // 2000 base - guess is capped at 30 FPS ~ 2 FPS error margin
//
//                      guess = 30

                CASE 1090 TO 1240                       // 1200 base - guess is 50 FPS ~ -2 to +5FPS error margin

                        guess = 50

                CASE 967 TO 1033                // 1000 base - guess is 60 FPS ~ 2 FPS error margin

                        guess = 60

                CASE < 909              // faster than 66 FPS

                        guess = -1              // throttle advised

                DEFAULT                 // do nothing

                        guess = 0               // we are lost somewhere

                        // do nothing

        ENDSELECT

        gstore[curguess] = guess        // assign new guess

        INC curguess    // increase the counter

        IF curguess = guessnum  // reached the end of the guesses needed

                curguess = 0    // reset loop

        ENDIF

        // run a check on all guesses.
        oldguess = gstore[0] // all guesses must be the same as this one to work
        FOR g = 1 TO guessnum-1

                IF gstore[g] <> oldguess        // if there is a difference

                        sameflag = FALSE

                ENDIF

        NEXT



        // now check to see if there is consistency
        IF sameflag = TRUE              // we have a recommended

                SELECT guess

                        CASE 60

                                IF SF_guess <> 60
                                        SF_curd# = 16.66666666666667    // frame time
                                        SF_guess = guess
                                        SF_fullflag = TRUE      // this app can run at 60FPS on the hardware
                                        SF_m = 0        // reset frame reading
                                ENDIF

                        CASE 50

                                IF SF_guess <> 50 AND SF_fullflag = 0           // not already 50 and has never been 60FPS
                                        SF_curd# = 20
                                        SF_guess = guess
                                        SF_m = 0        // reset frame reading
                                ENDIF

//                      CASE 30
//
//                              IF SF_guess <> 30
//                                      SF_curd# = 16.66666666666667    // keep the same frame time as 60 FPS because the timers will compensate
//                                      SF_guess = guess
//                                      SF_m = 0        // reset frame reading
//                              ENDIF

                        CASE -1

                                IF SF_guess <> -1
                                        SF_curd# = 16.66666666666667    // enforce 60 FPS because on very fast computer
                                        SF_guess = guess
                                        throttle = TRUE
                                        SF_m = 0        // reset frame reading
                                        LIMITFPS 60
                                ENDIF

                        CASE 0  // release the guess from memory

                                SF_guess = guess

                        DEFAULT

                                // do nothing

                ENDSELECT

        ELSE    // they are not the same!

                SF_guess = 0
                //SF_curd# = don't change because not sure!

        ENDIF

ENDIF   // end if reset = true

ENDFUNCTION




FUNCTION ReadControls:

MOUSESTATE mx, my, ma, mb

mx = (mx - xborder) / zoom
my = (my - yborder) / zoom

IF ma

        INC press

ELSE

        press = 0

ENDIF

ENDFUNCTION
 

Offline siatek

  • Mr. Drawsprite
  • **
  • Posts: 58
    • View Profile
Re: Some base code for Ludum Dare
« Reply #1 on: 2012-Sep-12 »
Thanks for sharing ... I must take a look :) 
glbasic roxx !!!