GLBasic forum

Main forum => Tutorials => Topic started by: sf-in-sf on 2013-Jul-24

Title: mainloop()
Post by: sf-in-sf on 2013-Jul-24
Hi!
Here is an attempt at running a "mainloop" for all objects at once, like in python. Interesting for gaming or GUI design. Objects of different types get created and deleted dynamically. It's also a solution to get an abstract class functionnality in GLb, without C++.
Have good fun!
Code: GLBasic [Select]
// --------------------------------- //
// Project: TYPE_1 (pure abstract classes in C++ failed)
// Start: Saturday, July 20, 2013
// IDE Version: 10.244


// --------------------------------- //
// Project: TYPE_2
// Start: Tuesday, July 16, 2013
// IDE Version: 10.244


// SETCURRENTDIR("Media") // go to media files
SETSCREEN 500,500,0
SYSTEMPOINTER FALSE
//LIMITFPS 30

GLOBAL oblist%[] AS ob // like a pure abstract class, an array of various objects.
//GLOBAL collist%[] ; DIMDATA collist%[],0xcc66ff,0x00bb55, 0x0055ff,0xcc7777, 0x777777
TYPE ob
        shape$ ="sq" // is the TYPE of each object, in fact.
                        // used later in a "switch" to apply the correct drawing function,
                        // like a function member of each object in C++.
        color% = 0x666666 //default color
        val1=0 ; val2=0 ; val3=0 // generic, use varies depending on the type of object.
        px ; py ; vx ; vy
//      weapons% =0
        intelligence% = 4 // (bonus included, haha)
        dizziness% =1
        bounces%=4 // max. bounces allowed, the deletion criterium.
ENDTYPE

start:
FOR bzzz% = 1 TO 440 ; new_ob() ; NEXT // create n objects
GLOBAL t0%, t% , stamp%
LOCAL ciao%
t0=GETTIMERALL() ; t=t0+2000

mainloop://____run_all_objects_at_once__________________._____________________
WHILE TRUE
        FOREACH z IN oblist[]
                ciao=animate(z)
                IF ciao >0 THEN DELETE z // [death]
                        //DELETE must be inside a loop, otherwise you need to know
                        // the (int) position of object z inside the array oblist[]. How do you get that?
                        // Please post me the answer if you know it.
        NEXT
        PRINT LEN(oblist[]), 5,5
        SHOWSCREEN
        stamp=GETTIMERALL() // MUST be GLOBAL apparently, too tricky otherwise.
        IF stamp >t
                t=t+500+RND(700) //1789+RND(1984)
                new_ob()  // [birth]
//              DRAWRECT 10,10,222,222, RGB(255,255,0) // visualize creation time
        ENDIF  
WEND
//______________________________________________________._____________________


FUNCTION new_ob:
        LOCAL z AS ob // new, inherits default values
//      z.color = collist[RND(4)]
        z.color = BOR(RND(0xffffff), ASL(0x000000f0,8*RND(2)))
                // avoiding dark or unsaturated colors.

        IF RND(1) // if shape is sq
                z.px =250.0 ; z.py =250.0
                z.vx =rnddr2() ; z.vy =rnddr2()
                z.val1=6+RND(30) ; z.val2=6+RND(30)
                        // more t.b.c.
        ELSE
                z.px =250.0 ; z.py =250.0
                z.vx =rnddr2() ; z.vy =rnddr2()
                z.shape$="tri" ; z.val1=RND(84)-42
        ENDIF
        DIMPUSH oblist[], z
ENDFUNCTION
FUNCTION animate: z AS ob

INLINE
 //moves, common, C-style:
                z.px +=z.vx ; z.py+=z.vy;
                if(z.px <50)
                        {z.vx =rnddr(); z.vy=rnddr2()  ; z.px=50;   z.bounces-=1 ; if (z.bounces <1) {return(7);}}
                if(z.py <50)
                        {z.vy =rnddr(); z.vx=rnddr2()  ; z.py=50;   z.bounces-=1 ; if (z.bounces <1) {return(7);}}
                if(z.px >450)
                        {z.vx = -rnddr(); z.vy=rnddr2(); z.px =450; z.bounces-=1 ; if (z.bounces <1) {return(7);}}
                if(z.py >450)
                        {z.vy = -rnddr(); z.vx=rnddr2(); z.py=450;  z.bounces-=1 ; if (z.bounces <1) {return(7);}}
               
ENDINLINE

//switch to apply the right function:
IF z.shape$ = "sq" // "according to the type" like an abstract class.
        DRAWRECT z.px,z.py,z.val1,z.val2,z.color
ELSEIF z.shape$="tri"
        STARTPOLY -1,1 //no texture, iMode=tri
                POLYVECTOR z.px, z.py-z.val1,   0,0, z.color
                POLYVECTOR z.px+10, z.py,       0,0, z.color
                POLYVECTOR z.px-10, z.py,       0,0, z.color
        ENDPOLY
ELSE
        // another default type of object.
ENDIF // ...should be usable to make a custom GUI.

RETURN 0 // i.e. "don't delete this element"
ENDFUNCTION
FUNCTION rnddr:
        RETURN (RND(3000)+5)/1000.0
ENDFUNCTION
FUNCTION rnddr2:
        IF (RND(1)) ; RETURN rnddr()
        ELSE
                RETURN -rnddr()
        ENDIF
ENDFUNCTION

 
Title: Re: mainloop()
Post by: Hemlos on 2014-Aug-16
Not intentionally bumping this dead thread...
But i must say, as rough as this code may be....
It is definetly a super powerful way to program anything at all.

Sf you python addict!
Good stuff here and i personally cant live without using routines this way too.
As a matter of fact, im in the procress of creating a very large lib/api.
Point is..my lib of object style code is designed in this way to use GLBasic native commands internally.
And the next module im adding is a database structure which absolutely needs this sort of schmema.

String.is$ = "hello world!"
String.upper()

~ "Hello World"
Title: Re: mainloop()
Post by: spacefractal on 2014-Aug-16
im did same sort of array loop for enemies in Karma Miwa and discovered there issues when DELETE a object in a for, which might cause the app to crash. Instead im used a struct (TYPE) which can make if the object is dead, and then remove those later on (often in the Paint() section), so its dont conflict.
Title: Re: mainloop()
Post by: MrPlow on 2014-Aug-16
My 2 cents worth:

I had numerous bugs and crashes early on in Viking Invaders due to delete objects in a for-loop.

I found it better to set a flag for the object status

obj.status = 1 // 0 = alive, 1=dead , etc...
cleanup  = true
.
.
// end of sequence
if cleanup then cleanup()

Function cleanup:
   // Perform
    Foreach i in vikings[]
        if obj.status = 1 then delete i
     Next
    Foreach b in boats[]
        if obj.status = 1 then delete b
     Next
endfunction

And if the game was depending upon animation of many screen objects I sometimes never deleted the objects as the speed of the game was sometimes slightly affected.
Title: Re: mainloop()
Post by: erico on 2014-Aug-16
...
I found it better to set a flag for the object status
obj.status = 1 // 0 = alive, 1=dead , etc...
...

Pretty much what I do too. :good:
Title: Re: mainloop()
Post by: kanonet on 2014-Aug-18
Did you do anything liek accessing dim size etc? Cause DELETE should not crash you (at least not on single dimension arrays, multi are bugged IIRC...) Would be interesting to know what caused your crash (and how to fix it).
Title: Re: mainloop()
Post by: Moru on 2014-Aug-18
Isn't this a sort of entity system? There are a few 2D and 3D starts of entity systems on the forums if you want to have a look.

In general: If the array is small, the most efficient is usually to delete items. If the array is very big it's better to just flag them active/inactive and overwrite with new data later because the release of memory and allocating more memory is slow.

I would be curious to see some code that crashes with delete in foreach loops because I have never had any problems with that.
Title: Re: mainloop()
Post by: sf-in-sf on 2014-Aug-22
 MrPlow, I'm totally with you about your fix. Yet I don't remember having any crash. So I agree with Kanonet, if DELETE inside a loop is safe, what else caused the crash?