Example: Invasion (3D Space Invaders Clone)
Check out this simple space invaders clone, featuring 3D UFO’s and UFO and player movement. This runs well on both the application and in the web version using modest hardware.
Rather than using hatchlings each with its own thread (worker), Invasion creates 15 static turtles representing each UFO, then iterates through moving them using the main (Myrtle) worker, more like a conventional single-threaded application would.
One procedure is used to generate randomly-colored UFO models, which are then assigned to each UFO turtle. The UFO turtles move in a 3D pattern created by ‘rolling’ them (rotating them on the Z axis), moving them left or right using slideleft and slideright, and raising and lowering them (using raise and lower) – a great exploration of 3D movement in turtleSpaces.
The code is commented and follows below. It’s also available inside the WebIDE under the menu FIle -> Browse Published…
NEWTURTLE "myrtle TO game ;invasion is a simple space invaders clone with a 3D twist reset release ;reset the workspace and release the non-standard turtles (ufos) stars:drawstars ;draw a starfield using the stars turtle nokeyclick ;don't click keys noaudiowait ;don't pause on audio playback snappy:newworker [ pullout 100 forever [ repeat 45 [orbitleft 1 wait 5] repeat 90 [orbitright 1 wait 5] repeat 45 [orbitleft 1 wait 5] repeat 45 [orbitup 1 wait 5] repeat 90 [orbitdown 1 wait 5] repeat 45 [orbitup 1 wait 5] ] ] ;create a new 'worker' to move the camera around the scene ;independently of other activity make "fleet [] share "fleet ;the fleet container holds the list of UFO turtle names ;it needs to be shared so all the UFO turtles can edit it make "score 0 share "score ;the score cotnainer holds the score, the number of UFOs destroyed ;the UFOs themselves increment the score, and so it must be shared repeat 3 [ repeat 5 [ newtu word repcount repabove 1 ;create a new turtle with the name column + row ;note: newtu is NOT the same as newturtle, newturtle is a ;declaration used in the workspace file (this), while newtu ;creates a new turtle during execution and selects it ;(we should change its name to instatiate?) noaudiowait makemodel ;create its UFO model queue turtle "fleet ;add the turtle name to the fleet container make "shootcount 0 ;reset its shootcounter to 0 penup ;don't draw anything! setposition {-225 + repcount * 75 -25 + (repabove 1) * 50} ;set its position based on its row and column number ;curly braces indicate a 'soft list', a list that is evaluated ;at runtime. repabove gets the loop count of the repeat enclosing ;the current repeat showturtle ;show the UFO ] ] ;create three rows of 5 UFOs each setturtle myrtle ;reselect myrtle setmodel "spaceship ;change myrtle's model to the built-in spaceship model setmodelscale 2 ;set the model's scale (size) to a factor of 2 penup back 150 ;position Myrtle newworker [ forever [ movefleet ;run the movefleet procedure toot 200 + random 1000 2 ;make a random beep wait 10 ] ] ;create a new 'worker' to move the UFOs 'forever' make "delay 0 ;stores the delay between player shots forever [ if :delay > 0 [dec "delay] ;decrease the delay value by one, if it is above zero if keyp [ ;if a key has been pressed: make "key uppercase readchar ;store the uppercase value of the key in the key container switch "key ;use the value of the key value for the following case comparisons: case "J [repeat 10 [repeat 10 [sl .1]]] case "K [repeat 10 [repeat 10 [sr .1]]] case "I [repeat 10 [repeat 10 [ra .1]]] case "M [repeat 10 [repeat 10 [lo .1]]] ;move Myrtle as required case "A [ ;should I shoot? if :delay = 0 [ ;yes, I should shoot! ;we're going to 'hatch' a missile BUT if we just ;do that, our detection routine will think we've been shot. ;to work around this, we're going to stop rendering our ;spaceship while we launch our missile from a position ;slghtly forward of our current position. notrackrender ;don't render this turtle's graphics forward 31 updatestate ;update the state of the turtle. This is usually done while ;rendering, so we need to do this manually while rendering is ;off hatch [ showturtle repeat 300 [fd 1] ] ;hatch our 'missile', which goes forward 300 steps and then 'dies' back 31 ;move back to where we were before trackrender ;turn track rendering back on playsound "pew ;play a 'pew' sound make "delay 20 ;set the delay container to 20, which causes us to have to wait ;before firing again ] ] ] if nearp 30 [ ;check to see if we've been hit. If we have: playsound "explosion hideturtle print |Boom! Game over!| repeat 50 [ randomfillcolor icosphere repcount wait 1 ] ;explosion animation clean finish ;finish stops all execution ] wait 1 ;wait 1/60ths of a second between loops ] ;do it again END TO movefleet ;this procedure moves the UFOs if :fleet = emptylist [ ;if there are no UFOs left: print |Great work!| playsound "applause wait 120 finish ] foreach "ufo :fleet [ ;for each of the UFOs remaining: setturtle :ufo ;select the ufo turtle rollright 10 ;roll right 10 degrees if 1 = last :ufo [slideright 5] if 1 = first :ufo [lower 5] if 2 = last :ufo [slideleft 5] if 2 = first :ufo [raise 5] if 3 = last :ufo [slideright 5] if 3 = first :ufo [lower 5] ;do a merry dance if :shootcount > 0 [dec "shootcount] if and 1 = random 20 :shootcount = 0 [ make "shootcount 20 hatch [ right 180 showturtle repeat 300 [fd 1 rr 1] ] ] ;fire! foreach "i near position 50 [ if "m = second :i [ht newworker [repeat 50 [ico repcount wait 1] clean] ;boom make "fleet without turtle :fleet ;remove ufo turtle from fleet list inc "score (print |Score:| :score) ;increase the score and tell the user playsound "explosion ;play an 'explosion' sound myrtle:try [halt hatchlingworker :i] [] ;stop the missle that shot me (if it still exists) ] ] ;you got me! ] tu myrtle ;reselect Myrtle END NEWTURTLE "snappy NEWTURTLE "libby TO makemodel ;make the UFO model for the calling turtle begintag turtle makeufo endtag newmodel word "ufo turtle turtle clearscreen ;this applies only to the calling turtle setmodel word "ufo turtle END TO makeufo ;create the UFO itself penup randomfillcolor make "sides 3 + random 6 down 90 rollright 180 torus 10 25 3 :sides ;make the outer ring switch {fc} case 1 [setfc 9] case 2 [setfc 7] case 3 [setfc 11] case 4 [setfc 12] case 5 [setfc 10] case 6 [setfc 2] case 7 [setfc 6] case 8 [setfc 13] case 9 [setfc 1] case 10 [setfc 15] case 11 [setfc 3] case 12 [setfc 14] case 13 [setfc 8] case 14 [setfc 12] case 15 [setfc 5] ; select a complementary fill color dome 25 3 :sides ;make the top dome polyspot 25 :sides ;make the bottom spot END NEWTURTLE "stars TO drawstars ;draw the starfield penup repeat 100 [ ;do 100 times: home ;go home randomvectors ;pick a random vector orientation forward 1000 + random 1000 up 90 randomfillcolor spot 5 + random 10 ;create a randomly colored 'star' ] END