GLBasic forum

Codesnippets => Code Snippets => Topic started by: Wampus on 2012-Aug-25

Title: Some base code for Ludum Dare
Post by: Wampus 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
Title: Re: Some base code for Ludum Dare
Post by: siatek on 2012-Sep-12
Thanks for sharing ... I must take a look :)