! planets -- you can play ! ! intro FN.DEF intro() txt$ = "This is a program for creating a toy solar system. " txt$ = txt$ + "You can create up to 10 planets by touching the screen. " txt$ = txt$ + "A planet will be created at that point " txt$ = txt$ + "with a velocity which will give it a near " txt$ = txt$ + "circular orbit. It will have a random " txt$ = txt$ + "mass(indicated by the size) and color. " txt$ = txt$ + "Gravitational interactions with other planets " txt$ = txt$ + "can cause orbital perturbations and your " txt$ = txt$ + "planet might collide with another one " txt$ = txt$ + "or escape to the Kuiper Belt. " txt$ = txt$ + "Pushing the green Menu button will allow " txt$ = txt$ + "you to print a snapshot of planetary " txt$ = txt$ + "parameters or to quit the program. " txt$ = txt$ + "There are totals for number of planets and " txt$ = txt$ + "collisions at the bottom of the screen. " txt$ = txt$ + "If the planet count is greater than the number you see, " txt$ = txt$ + "the planet is in a highly eccentric ellipse or parabola or txt$ = txt$ + "hyperbolic orbit. You can run the snapshot to see how " txt$ = txt$ + "many half pixels it is away from the sun." txt$ = txt$ + "\n\n" + "When you have finished reading this, " txt$ = txt$ + "hit the Back(leftmost) thingie in the status bar to expose " txt$ = txt$ + "the Finished button and push it.\n" TEXT.INPUT x$,txt$ FN.END ! ! distance function ! FN.DEF dist(x1,y1,x2,y2) d = SQR((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1)) IF d = 0 THEN d = 0.00000001 FN.RTN d FN.END ! ! $piece a la mumps !caution: delim$ is ยง as a regexp for better or worse FN.DEF p$(x$,delim$,pno) SPLIT y$[],x$,delim$ FN.RTN y$[pno] FN.END ! ! detect touch FN.DEF tap(x, y, timeout, mpyx, mpyy) t0 = CLOCK() DO GR.TOUCH touched,x,y t1 = CLOCK() UNTIL touched | (t1 - t0) >= timeout x = x*mpyx y = y*mpyy FN.RTN touched FN.END ! ! and untouch FN.DEF untap() DO GR.TOUCH xx,yy,zz PAUSE 1 UNTIL !xx FN.RTN 1 FN.END ! ! menu button graphic control FN.DEF menu_button(p,SUNRAD,maxy,centerx,x,y) IF p = 0 THEN GR.COLOR 255,175,200,150,1 GR.CIRCLE mb1,centerx,maxy - SUNRAD - 15,SUNRAD + 10 GR.COLOR 255,0,0,0,0 GR.CIRCLE mb2,centerx,maxy - SUNRAD - 15,SUNRAD + 11 GR.COLOR 255,0,255,0,1 GR.CIRCLE mb3, centerx,maxy - SUNRAD -15,SUNRAD GR.COLOR 255,0,0,0,0 GR.CIRCLE mb4,centerx,maxy - SUNRAD -15,SUNRAD+1 FN.RTN 0 ELSE IF x > centerx - SUNRAD & x < centerx + SUNRAD & y < maxy - 3 & y > maxy - 2*SUNRAD THEN ARRAY.LOAD pat[],100,100 VIBRATE pat[],-1 FN.RTN 1 ELSE FN.RTN 0 ENDIF ENDIF FN.END ! ! things happen when collisions occur FN.DEF thing_show(t[],x,y) FOR j = 1 TO 3 GR.MODIFY t[j],"left",x -32 GR.MODIFY t[j],"top",y-32 GR.MODIFY t[j],"right",x+32 GR.MODIFY t[j],"bottom",y +32 GR.SHOW t[j] NEXT j GR.MODIFY t[4],"x",x GR.MODIFY t[4],"y",y GR.SHOW t[4] GR.RENDER FN.END ! FN.DEF thing_hide(t[]) FOR jj = 1 TO 4 GR.HIDE t[jj] NEXT jj GR.RENDER FN.END ! ! define new planet - use pre-allocated object FN.DEF new_planet(x,y,num_planets,p[],MAXPLANETS,GM,centerx,centery, planet_ptr) IF num_planets >= MAXPLANETS THEN FN.RTN 1 FOR nexav = 1 TO MAXPLANETS IF p[nexav,5] = 0 THEN F_N.BREAK NEXT nexav p[nexav,1] = x p[nexav,2] = y p[nexav,5] = 10 + 90*RND() p[nexav,6] = SQR(10*p[nexav,5]) d2s = dist(x,y,centerx,centery) velocity = SQR(GM/d2s) p[nexav,3] = velocity*(y - centery)/d2s p[nexav,4] = -velocity*(x - centerx)/d2s GR.MODIFY p[nexav,7],"x",x GR.MODIFY p[nexav,7],"y",y GR.MODIFY p[nexav,7],"radius",p[nexav,6] GR.BITMAP.SCALE sptr, planet_ptr, 2*p[nexav,6], 2*p[nexav,6] p[nexav,14] = sptr GR.COLOR 195,p[nexav,8],p[nexav,9],p[nexav,10],1 GR.BITMAP.DRAW p[nexav,13], sptr, x - p[nexav,6],y- p[nexav,6] p[nexav,11] = CLOCK() GR.SHOW p[nexav,7] num_planets = num_planets + 1 FN.RTN 0 FN.END ! ! deallocate planet slot FN.DEF delete_planet(j,p[],num_planets,nplans) p[j,5] = 0 GR.HIDE p[j,7] GR.HIDE p[j,13] GR.BITMAP.DELETE p[j,14] num_planets = num_planets - 1 IF num_planets > 0 THEN GR.MODIFY nplans,"text","# planets: " + FORMAT$("##",num_planets) ELSE GR.MODIFY nplans,"text","# planets: 0" ENDIF FN.END ! ! planets array ! planets[planet,param], where param is: ! 1 x position,2 y position, 3 delta x, 4 delta y, 5 mass, 6 radius, 7 obj_ptr ! 8 r, 9 g, 10 b, 11 start time, 12 distance to sun, 13 bitmap object, 14 bitmap ptr ! ! global variables ! backkey_normal = 1 CALL intro() backkey_normal = 0 num_planets = 0 scollisions = 0 pcollisions = 0 MAXPLANETS = 10 DIM planets[MAXPLANETS,14] SUNRAD = 40 REALSUNRAD = 65 Grav = 6.673 Mass = 10E4 GM = Grav*Mass ! ! GR.OPEN 255,0,0,0,1,-1 PAUSE 300 GR.SCREEN origx,origy scale_h = 0.5 scale_w = 0.5 GR.SCALE scale_w,scale_h GR.BITMAP.LOAD sun_ptr,"sun.jpg" GR.BITMAP.LOAD planet_ptr,"planet127.png" GOSUB screen_setup GOSUB starfield ! ! allocate planet objects and assign them random colors FOR i = 1 TO MAXPLANETS planets[i,8] = 50 + RND()*195 planets[i,9] = 50 + RND()*195 planets[i,10] = 50 + RND()*195 GR.COLOR 255,planets[i,8],planets[i,9],planets[i,10],1 GR.CIRCLE planets[i,7],200,100+i*50,10 GR.HIDE planets[i,7] NEXT i GR.COLOR 255,255,255,0,1 REM GR.CIRCLE sun,centerx,centery,SUNRAD GR.BITMAP.DRAW sun, sun_ptr, centerx - REALSUNRAD , centery - REALSUNRAD DIM thing[4] GR.COLOR 255,255,127,0,1 GR.ARC thing[1],centerx - 32,maxy - 65,centerx + 32,maxy -1,0,60,1 GR.ARC thing[2],centerx -32,maxy - 65, centerx + 32,maxy -1,120,60,1 GR.ARC thing[3],centerx -32,maxy -65, centerx + 32,maxy -1,240,60,1 GR.COLOR 255,250,0,0,1 GR.CIRCLE thing[4],centerx,maxy-33,15 FOR i = 1 TO 4 GR.HIDE thing[i] NEXT i CALL menu_button(0,SUNRAD,maxy,centerx,x,y) GR.COLOR 255,255,255,255,1 GR.TEXT.SIZE 50 GR.TEXT.DRAW nplans,80,maxy -40,"# planets: 0" GR.TEXT.DRAW scols,centerx + 160,maxy - 40,"solar: 0" GR.TEXT.DRAW pcols,centerx + 440, maxy -40,"planetary: 0" GR.TEXT.DRAW cxx,centerx + 280,maxy - 95,"# collisions" GR.RENDER AUDIO.LOAD noise,"explode.mp3" ! ! main loop the_end = false DO GOSUB check_orientation IF num_planets > 0 THEN GOSUB move GOSUB accel GOSUB accel2 ENDIF x = 0 y = 0 IF tap(&x,&y,32-3*num_planets,1.0/scale_w,1.0/scale_h) THEN IF ! menu_button(1,SUNRAD,maxy,centerx,x,y) THEN x = new_planet(x, y, &num_planets, planets[],MAXPLANETS,GM,centerx,centery, planet_ptr) GR.MODIFY nplans,"text","# planets: " + FORMAT$("##",num_planets) GR.RENDER ELSE GOSUB menu ENDIF y = untap() ENDIF UNTIL the_end GR.CLOSE TTS.INIT PAUSE 100 PRINT "Congratulations!!!" x = scollisions + 2*pcollisions y$ = FORMAT$("###",x) ptext$ = "planet" IF y$=" " THEN y$ ="0" IF x<>1 THEN ptext$ = ptext$ + "s" TTS.SPEAK "You have destroyed " + y$ + ptext$ END ! ! in case of rotation check_orientation: GR.SCREEN testx,testy IF testx = origx THEN RETURN origx = testx origy = testy GOSUB screen_setup GR.MODIFY sun,"x",centerx GR.MODIFY sun,"y",centery RETURN ! screen_setup: maxx = origx/scale_w maxy = origy/scale_h centerx = maxx/2 centery = maxy/2 GR.CLS RETURN ! starfield: FOR xx = 1 TO 100 GR.COLOR 255,255,255,240,1 xstar = maxx*RND() ystar = maxy*RND() inc = 3*RND() GR.RECT foo,xstar,ystar,xstar+2 + inc,ystar+2+inc GR.RENDER NEXT xx RETURN ! ! move the planets; check for solar collisions move: FOR i = 1 TO MAXPLANETS IF planets[i,5] <> 0 THEN planets[i,1] = planets[i,1] + planets[i,3] planets[i,2] = planets[i,2] + planets[i,4] GR.MODIFY planets[i,7],"x",planets[i,1] GR.MODIFY planets[i,7],"y",planets[i,2] GR.MODIFY planets[i,13],"x",planets[i,1] - planets[i,6] GR.MODIFY planets[i,13],"y",planets[i,2] - planets[i,6] IF GR_COLLISION(planets[i,7],sun) THEN GOSUB collide_sun ENDIF NEXT i GR.RENDER RETURN ! ! compute acceleration towards sun; adjust velocity; check for interplanetary collisions accel: DIM clist[MAXPLANETS] collides = 0 FOR i= 1 TO MAXPLANETS IF planets[i,5] <> 0 THEN d2s = dist(planets[i,1], planets[i,2], centerx, centery) planets[i,12] = d2s accel = GM/(d2s*d2s) ax = accel*(centerx - planets[i,1])/d2s ay = accel*(centery - planets[i,2])/d2s planets[i,3] = planets[i,3] + ax planets[i,4] = planets[i,4] + ay FOR j = i + 1 TO MAXPLANETS IF planets[j,5] <> 0 THEN IF GR_COLLISION(planets[i,7],planets[j,7]) THEN clist[i] = 1 clist[j] = 1 collides = 1 ENDIF ENDIF NEXT j ENDIF NEXT i IF collides THEN GOSUB collide_planets UNDIM clist[] RETURN ! ! compute accelerations toward nearby planets; (re)adjust velocity accel2: FOR k = 1 TO MAXPLANETS IF planets[k,5] <> 0 THEN FOR j = k + 1 TO MAXPLANETS IF planets[j,5] <> 0 THEN d2p = dist(planets[k,1],planets[k,2],planets[j,1],planets[j,2]) IF d2p < 350 accel = Grav*planets[j,5]/(d2p*d2p) ax = accel*(planets[j,1] - planets[k,1])/d2p ay = accel*(planets[j,2] - planets[k,2])/d2p planets[k,3] = planets[k,3] + ax planets[k,4] = planets[k,4] + ay accel = Grav*planets[k,5]/(d2p*d2p) ax = accel*(planets[k,1] - planets[j,1])/d2p ay = accel*(planets[k,2] - planets[j,2])/d2p planets[j,3] = planets[j,3] + ax planets[j,4] = planets[j,4] + ay ENDIF ENDIF NEXT j ENDIF NEXT k RETURN ! ! solar collision -- make noise, flash graphic collide_sun: AUDIO.STOP AUDIO.PLAY noise CALL thing_show(thing[],centerx,centery) CALL delete_planet(i,planets[],&num_planets,nplans) PAUSE 250 CALL thing_hide(thing[]) scollisions = scollisions + 1 GR.MODIFY scols,"text","solar: " + FORMAT$("###",scollisions) GR.RENDER RETURN ! ! planet collision -- make noise, flash graphic collide_planets: AUDIO.STOP AUDIO.PLAY noise FOR k = 1 TO MAXPLANETS IF clist[k] THEN CALL thing_show(thing[],planets[k,1],planets[k,2]) CALL delete_planet(k,planets[],&num_planets,nplans) PAUSE 125 ENDIF NEXT k CALL thing_hide(thing[]) pcollisions = pcollisions + collides GR.MODIFY pcols,"text","planetary: " + FORMAT$("#####",pcollisions) GR.RENDER RETURN ! menu: PAUSE 100 GR.FRONT 0 CLS PAUSE 100 pr: INPUT "Continue(1), Quit(2), or Snapshot(3): ",n IF n = 1 THEN GOTO mout IF n = 2 THEN the_end = 1 GOTO mout ENDIF GOSUB report GOTO pr mout: GR.FRONT 1 PAUSE 100 RETURN ! ; listing of current planets report: IF num_planets < 1 THEN RETURN tnow = CLOCK() rl = 0 DIM rlist$[num_planets] FOR l = 1 TO MAXPLANETS IF planets[l,5] <> 0 THEN rl = rl +1 rlist$[rl] = FORMAT$("######",ROUND(planets[l,12])) + "," + STR$(l) ENDIF NEXT l tgstr$= "" PRINT " color mass velocity age distance to sun ARRAY.SORT rlist$[] FOR l = 1 TO num_planets ridxs$ = p$(rlist$[l],",",2) xdists$ = p$(rlist$[l],",",1) ridx = VAL(ridxs$) color$ = HEX$(planets[ridx,8]) + HEX$(planets[ridx,9]) tgstr$ = tgstr$ + color$ + HEX$(planets[ridx,10]) + " " tgstr$ = tgstr$ + FORMAT$("###",planets[ridx,5]) + " " veloc = SQR(planets[ridx,3]^2 + planets[ridx,4]^2) tgstr$ = tgstr$ + FORMAT$("###",veloc) + " " age = (tnow - planets[ridx,11])/1000 tgstr$ = tgstr$ + FORMAT$("#####",age) + " " xdist = VAL(xdists$) tgstr$ = tgstr$ + FORMAT$("######",xdist) + "\n" NEXT l PRINT tgstr$ ARRAY.DELETE rlist$[] PAUSE 7000 RETURN ! ! ONBACKKEY: IF ! backkey_normal THEN BACK.RESUME !