`Coding Challenge - ODE Ball Shooter `Bill Robinson `2-4-06 `Shoot boxes over the wall for 1000 points each `If a box bounces back behind you and falls, you lose 3000 points `Sometimes you have to shoot boxes moving toward you, to keep from losing 3000 points `When the back wall gets higher, you may need to shoot the box in the air, to get it over the wall. ` `Add your own level if you want - add data statements around line 100, change numlevels on line 28 if you add a level. ` set display mode 1024,768,32 sync on : sync rate 0 hide mouse set ambient light 10 color backdrop rgb(0,0,30) randomize timer() set camera range 1,20000 dim particles(30,5) dim levelinfo(10) dim blockinfo(10,30,2) dim targetinfo(100,5) #Constant WHITE=rgb(255,255,255) #Constant YELLOW=rgb(255,255,0) global numlevels=5 global level global levelflag global numballs global targetsleft global targetx#=1000.0 global targety#=300.0 global targetz#=-300.0 global hitnum global gravity# global screenxmax=1024 global screenymax=768 global screenwidth global screenheight global screenxcenter global screenycenter global screenzcenter `balls global ballx# global bally# global ballz# global maxballspeed# global ballflag global ballsatonce global maxballs=199 global ballcount global nextballptr global lastballtime global newballtime global balltiming=100 `walls global leftwall=0 global rightwall=2000 global floor=5 global ceiling=1000 global backwall=2000 global backwallheight global barrierheight `Camera - position camera 500,200,-800 global camx=1000 global camy=200 global camz=-800 global mxold `ODE - globals global odeballptr global numboxes global targetsleft `Particles global intParticleDelay global particlesptr global particlesflag leveldata: `level 1 - #boxes, followed by the x,y coords for each box - also change the global 'numlevels' on line 20 if you add a level data 12,150,0, 300,0, 450,0, 600,0, 750,0, 900,0, 1050,0, 1200,0, 1350,0, 1500,0, 1650,0, 1800,0 `level 2 data 16,400,0, 400,100, 400,200, 400,300, 800,0, 800,100, 800,200, 800,300, 1200,0, 1200,100, 1200,200, 1200,300, 1600,0, 1600,100, 1600,200, 1600,300 `level 3 data 15,700,0, 800,0, 900,0, 1000,0, 1100,0, 1200,0, 750,100, 1150,100, 800,200, 1100,200, 850,300, 1050,300, 900,400, 1000,400, 950,500 `level 4 data 20,900,0,900,100,900,200,900,300,900,400,900,500,900,600,900,700,900,800,900,900 data 1000,0,1000,100,1000,200,1000,300,1000,400,1000,500,1000,600,1000,700,1000,800,1000,900 `level 5 data 27,100,0, 150,100, 200,200, 250,300, 300,400, 350,500, 400,600, 450,700, 500,800, 550,900 data 1000,0, 950,100, 900,200, 850,300, 800,400, 750,500, 700,600, 650,700, 600,800 data 350,300, 400,200, 450,100, 500,0 data 750,300, 700,200, 650,100, 600,0 restore leveldata for i=1 to numlevels read levelinfo(i) for j=1 to levelinfo(i) read blockinfo(i,j,1) read blockinfo(i,j,2) next j next i screenwidth=screen width() screenheight=screen height() screenxcenter=screenwidth/2 screenycenter=screenheight/2 screenzcenter=0 rem --- make left wall make object box 310,3000,1100,2 yrotate object 310,90 color object 310,rgb(200,200,0) position object 310,0,500,1000 set object emissive 310,rgb(100,100,0) rem --- make right wall make object box 311,3000,1100,2 yrotate object 311,-90 color object 311,rgb(255,255,0) position object 311,2000,500,1000 rem --- make floor make object box 303,2100,2500,3 xrotate object 303,-91 :`floor is tilted so ball run off floor to be re-used color object 303,rgb(0,200,0) position object 303,1000,-7,700 :`was -2 for y rem --- make back wall make object box 304,2000,1000,150 color object 304,rgb(0,0,255) backwallcenter=-500 rem --- make ceiling make object box 305,2000,3000,2 xrotate object 305,90 color object 305,rgb(0,255,255) position object 305,1000,1000,1000 set object emissive 305,rgb(0,70,70) rem --- Create ODE tennis balls --- for i=1000 to 999+maxballs make object sphere i,30 set object i,1,1,0 color object i,rgb(255,0,0) set object collision off i position object i, -2000,-2000,-2000 :`move object WAY off screen next i rem Create Bazooka Tube make object cylinder 300,40 :`Tennis ball CANNON set object 300,1,1,0 scale object 300,42,250,42 color object 300,rgb(0,10,0) xrotate object 300,90 fix object pivot 300 `texture object 300,406 rem Create Pivot Cone for Bazooka make object cone 301,5 :`pivot for cannon `hide limb 301,0 glue object to limb 300,301,0 offset limb 300,0,0,25,0 rem make target ball make object sphere 302,10 :`Target ball set object 302,1,1,0 color object 302,rgb(255,255,255) `texture object 302,404 rem use my own collision for room walls and floor set object collision off 300 :`Bazooka set object collision off 301 :`Pivot cone for cannon set object collision off 302 :`target ball for aiming cannon rem position objects for room hide object 301 :`hide cannon pivot `position object 302,-1000,-1000,-1000 :`TARGET ball - move off screen for now position object 301,camx,camy,camz+100 `------------------------------------------------------- xpos=500 ypos=300 zpos=500 ` Create the ODE World ode start ode set world gravity 0,-.3,0 :`-.3,0 :`was 0,-20,0 ode set world step 0.3 :`was 0.05 ode set world erp (0.2)*2.5 :`error correction each step ode set world cfm (10^-5)*2.5 :`Constriant Force Mixing - ` Create a static floor, walls, ceiling. ` Implement in Dark Basic Professional first (above) ` and then ask ODE to do the same... ode create static box 303 :`floor ode create static box 305 :`ceiling ode create static box 310 :`left wall ode create static box 311 :`right wall `ode set contact bounce 304,1 ` Create dynamic sphere ` Implement in Dark Basic Professional first ` and then ask ODE to do the same... make object sphere 400,120,16,16 :`Make sphere in DBPro first position object 400, xpos-50,ypos+200,zpos :`Position object in DBPro ode create dynamic sphere 400 :`Create same object in ODE, will have same position in ODE ode set body mass 400,10 :`Set object MASS ode set contact fdir1 400,30.0 :`Add FRICTION `-------------------------------------------------------- `ODE floor is higher so balls seem to roll on the floor, and not 'IN' the floor `Visible DBPro floor is lower, repositon it now, since ODE copy is made position object 303,1000,-5,700 :`was 1000,-2,1000 nextballptr=100 :`pointer into array - points to next ball to fire odeballptr=1000 ballcount=0 :`how many balls in use, on the screen ballsatonce=100 :`how many balls on screen at the same time numballs=5000 :`number of balls to shoot maxballspeed#=8 :`how fast should the balls shoot balltiming=100 :`pause between each ball being fired gravityon=1 :`gravity is on levelflag=0 level=1 :`start at this level gravity# = 0.1 position camera camx,camy,camz point camera targetx#,targety#,targetz# position mouse screenxcenter,screenycenter mxold#=mousex() numboxes=levelinfo(level) _textures() texture object 400,3 do if levelflag=0 _build_level(level) _InitParticles() endif position camera camx,camy,camz position object 301,camx,camy-40,camz-30 mx#=2000.0/screenwidth*mousex() :`get mouse x location my#=1000.0/screenheight*mousey() :`get mouse y location if mx#<>mxold# targetx#=mx# targety#=screenheight-my# mxold=mx if targetx#<0 then targetx#=0 if targetx#>2000.0 then targetx#=2000.0 :`limit target position to 1000, instead of 1024 which is past wall endif point object 301,targetx#,targety#,targetz# :`pivot cone points to target position object 302,targetx#,targety#,targetz# :`target ball moves as the target object point camera targetx#,targety#,targetz# keypress=scancode() :`scan for keys pressed, subroutine to hadle keys if keypress>0 then _key_action(keypress) mouse=mouseclick() :`get mouse click for firing tennis ball if mouse=1 then gosub _fire_tennis_ball :`FIRE! gosub _show_score :`show score on screen intParticleDelay=_check_event_triggers(1,numboxes,1) `is it time to turn particles emission to zero for an object for i=1 to numboxes if particles(i,5)>0 t=timer() delay=particles(i,5) delay2=delay-500 if t>delay set particle emissions i,0 particles(i,5)=0 endif endif next i `check for Boxes leaving the room for i=1 to numboxes if object exist(i) delflag=0 `Box shot off far end of screen - GOOD! if object position y(i)<0 and object position z(i)>backwall inc score,1000 delflag=1 else ` Box has fallen off behind player - deduct 5000 from score - BAD! if object position z(i)<camz and object position y(i)<-400 dec score,3000 delflag=1 endif endif if delflag=1 ode destroy object i delete object i dec targetsleft targetinfo(i,1)=0 endif endif next i if targetsleft=0 for pf=1 to numboxes if particles(pf,5)<>0 then particlesflag=1 next pf if particlesflag=0 _finished_level(level) inc level levelflag=0 endif endif ode update :`let ODE update physics sync loop ode end end rem --- show score on screen _show_score: ink rgb(255,255,255),0 set cursor 1,1:print screen fps() center text screenxcenter,2,"Level:"+str$(level)+" Targets Left: "+str$(targetsleft)+" Score: "+str$(score) if level=20 then center text screenxcenter,28,"Targets Left="+str$(level20targets) return rem ---------- fires tennis balls ---------- _fire_tennis_ball: if ballcount=ballsatonce then return newballtime=timer() if newballtime-lastballtime<balltiming then return else lastballtime=newballtime :`control firing rate of tennis balls if numballs=0 :`out of tennis balls to shoot retryflag=1 :`set retry flag, do you want to try this level again? return :`sound 3 = your gun is empty endif ballx#=object position x(301) :`get bazooka pivot location to start ball at bally#=object position y(301) ballz#=object position z(301) ballxi#=(targetx#-ballx#)/300.0*maxballspeed# :`calculate some value to move ball each time toward target ballyi#=(targety#-bally#)/300.0*maxballspeed# :`mostly an arbitrary calculation, to get lots of slices ballzi#=(targetz#-ballz#)/300.0*maxballspeed# :`build screen routine then says how many slices each move `----------- ODE STUFF ------------------------------------------------------------------- position object odeballptr,1000,100,-800 :`velocity 100 - was 1000,150,-800 `position object odeballptr,ballx#,bally#,ballz# :`start ball in bazooka point object odeballptr,targetx#,targety#,-50 ode destroy object odeballptr ode create dynamic sphere odeballptr ode set body mass odeballptr,20 :`was 20 ode set contact bounce odeballptr,1 ode set linear velocity odeballptr,ballxi#*75.0,ballyi#*75.0,1000.0 :`targetz=0,use*48, -300 use 75 `velocity of 1000 - for targetz locataion use - targetz=0,use*48 for xi# and yi#, -300 use 75 `velocity of 2000 - use *75.0 for aiming - fudged numbers, shound fix this later `inc ballcount :`one more ball on screen dec numballs :`one less ball you can fired inc odeballptr if odeballptr>999+maxballs odeballptr=1000 endif `----------------------------------------------------------------------------------------- return function _finished_level(level) set cursor 1,200 print "YOU FINISHED LEVEL - ";level print "Press a key to continue" sync wait key for i=1 to levelinfo(level) if object exist(i) ode destroy object i delete object i delete particles i endif targetinfo(i,1)=0 next i if level=numlevels print " " print "That's all there is for now - Thanks for Playing!" print "Press a key to exit game - Bye!" sync wait key end endif endfunction function _check_event_triggers(objmin,objmax,trigtype) for i=objmin to objmax if object exist(i) objx=object position x(i) :`get bazooka pivot location to start ball at objy=object position y(i) objz=object position z(i) select trigtype case 1 if objz>backwall and objy<backwallheight :`and targetinfo(i,1)=1 :`level*200 intParticleDelay=_sparks(i) ` dec targetsleft ` targetinfo(i,1)=0 endif endcase endselect endif next i endfunction intParticleDelay function _sparks(objnum) sparkx=object position x(objnum) :`get bazooka pivot location to start ball at sparky=object position y(objnum) sparkz=object position z(objnum) position particles objnum,sparkx,barrierheight,sparkz show particles objnum color particles objnum, rnd(255),rnd(255),rnd(255) particles(objnum,5)=Timer()+500 endfunction intParticleDelay function _InitParticles() for i=1 to numboxes if particles exist(i)=0 make particles i,0,250,30 color particles i, 255, 200, 200 set particle emissions i,30 :`was 30 set particle speed i, 0.2 :`0.20 set particle gravity i,.1 :`was 10 set particle life i,500 hide particles i endif next i endfunction function _key_action(keypress) select keypress case 20 if level>=8 balltiming=balltiming-10 wait 100 if balltiming<40 then balltiming=100 endif endcase endselect endfunction function _textures() for i=1 to 3 create bitmap i,50,50 if i=1 then ink rgb(255,0,0),0 if i=2 then ink rgb(255,255,0),0 if i=3 then ink rgb(255,0,255),0 for x=1 to 1000 ang=rnd(360) rad=rnd(20) dot 25+sin(ang)*rad,25+cos(ang)*rad next x blur bitmap i,1 get image i,0,0,50,50 delete bitmap i next i endfunction function _build_level(level) numboxes=levelinfo(level) targetsleft=numboxes for i=1 to numboxes make object box i,100,100,80 position object i,blockinfo(level,i,1),blockinfo(level,i,2)+50,900 :`+60 for y, because the floor is tilted from back-to-front color object i,rgb(rnd(255),rnd(255),rnd(255)) ode create dynamic box i ode set body mass i,20 ode set contact fdir1 i,25.0 targetinfo(i,1)=1 :`target is active next i if level<6 barrierheight=level*100 else barrierheight=6*100 endif position object 304,1000,-500+barrierheight,2000 :`position backwall ode create static box 304 :`tell ODE about backwall levelflag=1 endfunction