` D a r k B A S I C ` C L A S S I C ` Programming Challenge: ` Gadget/Minigame Collection ` My entry: ` SPT Date,Clock Gadget and Feed the Fish Game ` Author: Steve Paul Thomas ` Date: 14th November 2008 ` Credit due to: ` NanoGamez guy - for explaining how to work ` out the angles for the clock hands :) ` Latch - for showing me the use of the DATA ` commands and giving advice on how to better ` indent my code - hope the code is easier ` to read now. ` Comments ` Hope this isnt too bad for my first entry ` in the DBC Programming Challenge. ` Writing this taught me a lot on how to use ` various DB commands and I tried to use ` quite a fair few of them. ` ` Game: Feed The Fish ` Aim: Use your mouse to drop food for the hungry ` fish. He might be hungry, but he's also an idiot. ` So you have to drop the foodbits so they hit ` him. You get a +1% increase in health for each ` foodbit that touches him. ` Areas for Improvement: ` If I could dedicate more time to this I would have added: ` > Fish to swim away from mouse pointer if you get too close to it ` (as the game is at the moment, its kind of easy to just click on ` the fish) ` Scenery - wobbly seaweed (using sines?) and other cool stuff found ` in fish tanks ` Maybe add some useful tools or stuff related to the fish tank. ` If anyone wants to improve on this or even make some derivative of ` it, I'd love to see it :) ` Anyway here it is... rem All images are generated by code: rem Image 1: Date rem Image 2: Time rem Image 3: Goldfish rem Image 4: Foodbits rem Image 5: Fish Food Pot rem Image 6: Fish Health rem Images 13-22 are for the buttons rem Image 23 is for the button holder sprite,y=205 rem Sprite 1: Date rem Sprite 2: Time rem Sprite 3: Goldfish rem Sprites 4-10 are reserved for the foodbits rem Sprite 11 is the fish food pot that we attach to the mouse pointer rem Sprite 12 is the fish health sprite rem Sprites 13-17 are the buttons rem Manual refresh sync on rem Hide the default mouse pointer hide mouse rem Year prefix, yyprefix$ = "20" rem Thanks to Latch for pointing out this way rem to populate the array rem The names of the calendar months dim month_name$(12) rem Point at the start of the months list restore _months rem Read the months list into the array for i=1 to 12 read month_name$(i) next i rem Foodbits are the bits of fish food. rem We keep track of where they on the rem screen using this array. dim foodbits(7,2) rem 7 bits of food assigned to sprites rem 4 to 10. Since a sprite needs an rem x coordinate and a y coordinate rem we have two boxes inside each rem foodbits drawer (assuming you rem visualise arrays as drawers and boxes!) rem X coordinate for i = 1 to 7 foodbits(i,1) = 320 next i rem Y coordinate for i = 1 to 7 foodbits(i,2) = 650 next i rem Where the goldfish actually is on the screen fishx = 320 fishy = 240 rem How much health the fish has - if it reaches rem zero then he dies fish_health = 100 rem How many milliseconds pass before we remove some health from the fish fish_diminish_rate = 1000 rem How much percent of health should be removed each rem time the diminish_rate elapses fish_diminish_amount = 1 rem When we last subtracted some health - this one just initalises it last_diminish_time = timer() rem An integer that acts like a boolean (1 = pause, 0 = do not) pause_diminish = 0 rem Horizontal and vertical direction keepers rem If vdirection is set to zero string then rem the fish only moves left and right hdirection$ = "left" vdirection$ = "" rem Play with these values to alter difficulty rem Leave this at normal and use the buttons in the game to change rem difficulty level$ = "normal" rem The number of pixels per move interval speed = 8 rem How often to actually move in milliseconds move_interval = 50 rem Last time the fish moved last_move = timer() rem Last time we picked a new vertical direction rem - this makes the fish appear to move about rem aimlessly like...well like a goldfish! last_vdirection = timer() rem Set how a random amount of time that must elapse rem before we choose another direction. 0-10 seconds vdirection_interval = rnd(10000) rem Easily configurable colours of stuff... rem If you dont like the default sidebar colour then you rem can change it here (default is a blue-grey colour) sidebar = rgb(100,100,180) rem Colour of the hour hand and the hour blocks on the clock rem Default is red hourcolour = rgb(255,0,0) rem Colour of the minute hand and minute blocks on the clock rem Default is yellow minutecolour = rgb(255,255,0) rem Colour of the second hand on the clock rem Default is grey secondcolour = rgb(60,60,60) rem Make the background rem wipe screen with dark blue cls rgb(0,0,155) rem Now make some yellow sand ink rgb(220,180,22),0 box 0,400,639,479 rem Add some random dots to make it more interesting ink rgb(50,50,0),0 for i=1 to 1000 dot rnd(640),400 + rnd(475) next i rem Grab it and put it in a stupidly high image number get image 65000,0,0,640,480 cls 0 rem End of making the background rem Create an offscreen drawing area create bitmap 1,640,480 cls 0 rem Set the program up gosub _make_date_sprite gosub _make_clock_sprite gosub _make_button_holder_sprite gosub _make_goldfish_sprite gosub _make_fishstuff gosub _make_fish_health_sprite gosub _make_buttons rem Goldfish sprite sprite 3,fishx,fishy,3 rem Boost the fish size by 10 scale sprite 3,fish_health+10 rem ------------------- Main Program Loop ---------------------------- do rem Clear the screen with black cls 0 rem Paste the background, we will draw everything else after this paste image 65000,0,0 rem Date box sprite sprite 1,512,0,1 rem Clock box sprite sprite 2,512,65,2 gosub _move_fish rem Goldfish sprite sprite 3,fishx,fishy,3 if mydate$ <> get date$() then gosub _make_date_sprite if mytime$ <> get time$() then gosub _make_clock_sprite rem Check if its time to dimish fish's health if (timer() - last_diminish_time) >= fish_diminish_rate rem Knock health off fish gosub diminish_fish endif rem Health sprite sprite 12,10,10,6 rem Probably could have done this better with select and case rem statements, maybe next time, eh? sprite 23,512,205,23 rem Easy button if (level$ = "easy") sprite 13,512,205,18 else sprite 13,512,205,13 endif rem Normal button if (level$ = "normal") sprite 14,512,225,19 else sprite 14,512,225,14 endif rem Hard button if (level$ = "hard") sprite 15,512,245,20 else sprite 15,512,245,15 endif rem New Fish button if ((mousex() >= 512 and mousex() <= 639) and (mousey() >= 286 and mousey() <= 302) and mouseclick()=1) sprite 16,512,285,21 gosub _newgame sleep 250 else sprite 16,512,285,16 endif rem Exit button if ((mousex() >= 512 and mousex() <= 639) and (mousey() >= 306 and mousey() <= 322) and mouseclick()=1) sprite 17,512,305,22 sync sleep 500 end else sprite 17,512,305,17 endif rem See if any food has touched the fish sprite gosub _has_fish_eaten rem Keep the fish falling if its on the screen gosub _keep_food_falling rem Use the new foodbits x and y coordinates rem to update the foodbits sprites sprite 4,foodbits(1,1),foodbits(1,2),4 sprite 5,foodbits(2,1),foodbits(2,2),4 sprite 6,foodbits(3,1),foodbits(3,2),4 sprite 7,foodbits(4,1),foodbits(4,2),4 sprite 8,foodbits(5,1),foodbits(4,2),4 sprite 9,foodbits(6,1),foodbits(6,2),4 sprite 10,foodbits(7,1),foodbits(7,2),4 rem Fish food can sprite sprite 11,mousex(),mousey(),5 rem Did user toggle easy? if (mouseclick()=1 and mousex() >= 512 and mousex() <= 639) if (mousey() >= 206 and mousey() <= 222) level$ = "easy" speed = 4 fish_diminish_amount = 1 endif endif rem Did user toggle normal? if (mouseclick()=1 and mousex() >= 512 and mousex() <= 639) if (mousey() >= 226 and mousey() <= 242) level$ = "normal" speed = 6 fish_diminish_amount = 1 endif endif rem Did user toggle hard? if (mouseclick()=1 and mousex() >= 512 and mousex() <= 639) if (mousey() >= 246 and mousey() <= 262) level$ = "hard" speed = 12 fish_diminish_amount = 2 endif endif if mouseclick()=1 then gosub _make_food sync loop rem End of Main Program Loop ` (((((((((((((((((((( S U B R O U T I N E S )))))))))))))))))))))))))) remstart This subroutine creates a blue box with the date inside, formatted as: MONTH DATE NUMBER YYYY remend _make_date_sprite: rem Assign the DB date to mydate variable mydate$ = get date$() rem Extract the first two chars and assign to month month$ = left$(mydate$,2) rem If less than ten then bin the leading zero rem to make comparison with the month name array rem easier if val(month$) < 10 month$ = mid$(month$,2) endif rem Look at the month number as a number and use it as rem an index to what month name is. Finally assign rem month name to month month$ = month_name$(val(month$)) rem Just an excuse to use the upper case command month$ = UPPER$(month$) rem Extract the two characters from the middle and rem assign to daynum (the date, 1-31) daynum$ = mid$(mydate$,4) daynum$ = daynum$ + mid$(mydate$,5) rem If daynum is less than ten then bin the leading zero rem just because I feel like it ;) if val(daynum$) < 10 daynum$ = mid$(daynum$,2) endif rem Extract the year part year$ = right$(mydate$,2) rem Turn yy into yyyy by prefixing it year$ = yyprefix$ + year$ `print "DB Date: ";mydate$ `print "Day Number: ";daynum$ `print "Month: ";month$ `print "Year: ";year$ set current bitmap 1 rem Set pen color to sidebar colour and draw a box ink sidebar,0 box 0,0,128,64 rem Draw a border... rem Right and top in white ink rgb(255,255,255),0 line 128,64,128,0 line 128,0,0,0 rem Do a basic horizontal centre by using number of characters rem point size 10 is 10 pixels per char approx posx = 64 - (5 * len(month$)) rem Print month name ink rgb(255,255,255),0 set text font "arial" set text size 10 text 2+posx,2,month$ rem Print day number of the month set text size 32 rem Do another basic horizontal centre posx = 64 - (13 * len(daynum$)) text posx,10,daynum$ rem Print year set text size 10 text 50,50,year$ get image 1,0,0,128,64 cls set current bitmap 0 return remstart This function creates an analogue clock with digital time underneath it. Credit to NanoGamez guy for explaining how to calculate the angle on the fly, rather than use a huge list of angles for every hour, minute and second. remend _make_clock_sprite: rem Assign DB time to mytime variable mytime$ = get time$() set current bitmap 1 rem Clear the screen with the sidebar colour cls sidebar rem This bunch of code puts yellow blocks at 6degree rem points around the face, then you get one block for rem each minute of the clock face minutesradius = 50 minutesangle# = 0.0 minutes_step# = 6.0 rem Switch to minutecolour pen ink minutecolour,0 rem Draw the minute blocks for i = 0 to 60 minutesx = minutesradius * cos(minutesangle#) minutesy = minutesradius * sin(minutesangle#) box (minutesx + 320)-1,(minutesy + 240)-1,minutesx+320+2,minutesy+240+2 minutesangle# = wrapvalue(minutesangle# + minutes_step#) next i rem End of minute block drawing rem Extract the minute from mytime myminute$ = mid$(mytime$,4) myminute$ = myminute$ + mid$(mytime$,5) rem The angle of a minute is: (minute / 60) * 360 -90 anglem = (((val(myminute$) / 60) * 360) -90) line 320,240,(40 * cos(anglem))+320,(40 * sin(anglem))+240 rem Switch to secondhand pen ink secondcolour,0 rem Extract the seconds from mytime myseconds$ = right$(mytime$,2) rem The angle of a second is: (second / 60) * 360 -90 angles = (((val(myseconds$) / 60) * 360) -90) line 320,240,(40 * cos(angles))+320,(40 * sin(angles))+240 rem This bunch of code puts red blocks at 30 degree rem points around the face, then you get one block for rem each hour of the clock face hoursradius = 50 hoursangle# = 0.0 hours_step# = 30.0 rem Switch to hourhand pen ink hourcolour,0 for i = 1 to 12 hoursx = hoursradius * cos(hoursangle#) hoursy = hoursradius * sin(hoursangle#) box (hoursx + 320)-1,(hoursy + 240)-1,hoursx+320+2,hoursy+240+2 hoursangle# = wrapvalue(hoursangle# + hours_step#) next i rem End of block drawing rem Extract the hour from mytime myhours$ = left$(mytime$,2) rem The angle of an hour is: (hour / 12) * 360 -90 angleh = (((val(myhours$) / 12) * 360) -90) rem Just to add some inbetweening rem If its quarter past the hour to just before half past if (val(myminute$) >= 15) and (val(myminute$) < 30) angleh = wrapvalue(angleh +6) endif rem If its half past the hour to just before quarter to if (val(myminute$) >= 30) and (val(myminute$) < 45) angleh = wrapvalue(angleh +12) endif rem If its quarter to the hour to just before hour if (val(myminute$) >= 45) and (val(myminute$) <= 59) angleh = wrapvalue(angleh +18) endif rem Draw hour hand line 320,240,(30 * cos(angleh))+320,(30 * sin(angleh))+240 rem Set pen colour to white and draw a big circle for the clock face ink rgb(255,255,255),0 clockradius = 55 clockangle# = 0.0 clock_step# = 1.0 rem Draw outer circle of clock face for i = 0 to 360 clockx = clockradius * cos(clockangle#) clocky = clockradius * sin(clockangle#) box (clockx + 320)-1,(clocky + 240)-1,clockx+320+2,clocky+240+2 clockangle# = wrapvalue(clockangle# + clock_step#) next i rem End of block drawing rem Draw a border... rem Right and top in white ink rgb(255,255,255),0 line 384,320,384,180 line 384,180,256,180 rem Set pen to white ink rgb(255,255,255),0 set text font "arial" set text size 10 rem Write out the full time in digital form center text 320,300,mytime$ rem Capture the image and place in image slot 2 get image 2,256,180,384,320 rem Switch canvas back to the screen set current bitmap 0 rem Return to Main Program Loop return _make_button_holder_sprite: set current bitmap 1 rem Clear the screen with a pale blueish colour cls sidebar rem Get image for use as the button holder get image 23,0,0,128,275 set current bitmap 0 return rem Quite simply this sub does some drawing rem to create a crude goldfish. I was kind rem of lazy with this as wanted a quick result _make_goldfish_sprite: set current bitmap 1 cls 0 rem Set pen to orange ink rgb(239,84,0),0 fishh = 1 rem Quick way of drawing a filled ellipse for fishw = 1 to 25 ellipse 25,10,fishw,fishh if fishh < 10 then inc fishh next fishw rem End of drawing filled ellipse rem Cover over the dots box 18,4,34,18 rem Now to draw the tail for i=4 to 14 line 50,10,65,i next i rem The back line of the tail line 65,4,65,14 rem Make an eyeball ink rgb(255,255,255),0 for i = 0 to 4 circle 16,8,i next i rem Make a green pupil ink rgb(0,128,0),0 for i = 0 to 2 circle 14,8,i next i rem Grab image of fish get image 3,0,0,66,22 rem Return drawing to screen set current bitmap 0 return _make_fishstuff: set current bitmap 1 cls 0 rem Make orange fish food piece and grab image ink rgb(255,164,33),0 box 0,0,2,2 get image 4,0,0,2,2 cls 0 rem Set pen colour to yellow ink rgb(255,255,0),0 rem Draw a pot of fish food rem this will track the mousex and mousey rem and food will appear to fall out of it rem when the mouse is clicked line 12,0,17,5 line 10,0,17,7 line 10,1,16,7 line 9,1,16,8 line 9,2,15,8 line 8,2,15,9 line 8,3,14,9 line 7,3,14,10 line 7,4,13,10 line 6,4,13,11 line 6,5,12,11 line 5,5,12,12 line 5,6,11,12 line 4,6,11,13 line 4,7,10,13 line 3,7,10,14 line 3,8,9,14 line 2,8,9,15 line 2,9,8,15 line 1,9,8,16 line 1,10,7,16 line 10,10,7,17 rem Set pen colour to blue ink rgb(0,0,255),0 rem Draw an F at an angle line 4,10,10,4 line 7,7,9,9 line 10,4,13,7 rem Extract image and put food pot into image 5 get image 5,0,0,18,18 cls 0 rem Place the sprites offscreen for i = 4 to 10 sprite i,320,650,4 next i rem Set canvas to screen set current bitmap 0 rem Return to Main Program Loop return rem This sub grabs the mouse pointers x and y coordinates rem then creates a random (but small) offset from them rem this gives the appearance of sprinkles of food falling rem out of the pot. _make_food: mx = mousex() my = mousey() rem For all 7 foodbits for i = 1 to 7 rem Check foodbits i is offscreen and mouse isnt over sidebar rem if we meet both these conditions then its OK to render rem foodbits i on screen if foodbits(i,2) >= 400 and mousex() < 482 foodbits(i,2) = my + rnd(4) + 2 foodbits(i,1 = mx + rnd(10) + 18 endif next i return rem If foodbits i y coordinate is less than screen (plus 10) rem then increment its y coordinate to make it appear to fall. rem Repeat for all 7 foodbits. _keep_food_falling: curvalue = 0 for i = 1 to 7 if foodbits(i,2) < 400 curvalue = foodbits(i,2) inc curvalue,2 foodbits(i,2) = curvalue endif next i return rem This is simply a text indication of how rem much health the fish has left _make_fish_health_sprite: set current bitmap 1 cls 0 rem Set pen to orange ink rgb(239,84,0),0 set text font "arial" set text size 16 rem Convert the fish_health value to a string and append to Health literal healthstring$ = "Health: " + str$(fish_health) + "%" rem Render text text 0,0,healthstring$ rem Grab an image ready for use as a sprite get image 6,0,0,128,22 rem Switch canvas back to screen set current bitmap 0 rem Back to the Main Program Loop return rem This slowly diminishes the fish's health over time diminish_fish: if fish_health >0 and pause_diminish = 0 rem Decrease health by 1% dec fish_health,fish_diminish_amount rem Update the Fish Health Sprite gosub _make_fish_health_sprite rem Shrink the fish everytime it loses health rem Scale by health, plus another 10 or the fish would get rem small to quickly scale sprite 3,fish_health+10 rem When we last subtracted some health - this one just initalises it last_diminish_time = timer() endif if fish_health >0 and pause_diminish = 1 rem Update the Fish Health Sprite gosub _make_fish_health_sprite rem Shrink the fish everytime it loses health rem Scale by health, plus another 10 or the fish would get rem small to quickly scale sprite 3,fish_health+10 rem Add a 2 second pause last_diminish_time = timer() + 2000 rem Reset pause diminish now we are done with it pause_diminish = 0 endif _make_buttons: makebutton("Easy",13) makebutton("Normal",14) makebutton("Hard",15) makebutton("New Fish",16) makebutton("Exit",17) makebuttonpressed("Easy",18) makebuttonpressed("Normal",19) makebuttonpressed("Hard",20) makebuttonpressed("New Fish",21) makebuttonpressed("Exit",22) return rem If fish has got more than 0% health then he can move _move_fish: rem Decide if its time to move if ((timer() - last_move) > move_interval) and fish_health > 0 rem If fish is not touching left of screen and is rem looking left then move him left a bit if (fishx > 20) and hdirection$ = "left" dec fishx,speed endif rem If fish has reached left edge of tank (screen) if (fishx <= 20) mirror sprite 3 hdirection$ = "right" endif rem If fish is not touching right of screen and is rem looking right then move him right a bit if (fishx < 446) and hdirection$ = "right" inc fishx,speed endif rem If fish has reached right edge of tank (screen) rem (marked by sidebar) if (fishx >= 446) mirror sprite 3 hdirection$ = "left" endif rem Choose a new vertical direction only if its time to (determined by rem a random interval - which is set on each direction change) if (timer() - last_vdirection) > vdirection_interval gosub _up_down_none rem Make this event happen in a random 1-10 seconds time vdirection_interval = rnd(10000) rem Make a note of the timer to compare with random interval last_vdirection = timer() endif rem If looking up and still not touched top of screen if (vdirection$ = "up") and fishy > 40 dec fishy,2 endif rem If looking down and still not touched bottom if (vdirection$ = "down") and fishy < 370 inc fishy,2 endif rem Since we just moved, make a note of what the timer rem reading is. last_move = timer() endif return rem Direction chooser subroutine _up_down_none: rem Randomly choose a direction 0,1 or 2 chosendir = rnd(2) select chosendir case 0: vdirection$ = "" : endcase case 1: vdirection$ = "up" : endcase case 2: vdirection$ = "down" : endcase endselect return _has_fish_eaten: rem For all 7 foodbits for i = 1 to 7 rem Are the food bits vertically colliding with fish? if foodbits(i,2) >= fishy and foodbits(i,2) <= fishy + sprite height(3) rem Now check horizontally - if so then the food has touched the fish sprite if foodbits(i,1) >= fishx and foodbits(i,1) <= fishx + sprite width(3) rem Reset the foodbit to offscreen foodbits(i,2) = 650 rem Increase health a bit inc fish_health pause_diminish = 1 endif endif next i rem Correct fish health if it is too big if fish_health > 100 then fish_health = 100 return _newgame: rem Restore health to 100 fish_health = 100 rem Boost the fish size by 10 scale sprite 3,fish_health+10 rem Set diminish time to now last_diminish_time = timer() rem Ensure diminish is active pause_diminish = 0 fishx = 320 fishy = 240 return ` (((((((((((((((((((( F U N C T I O N S )))))))))))))))))))))))))) function makebutton(caption$,buttonnum) set current bitmap 1 cls 0 rem The purple body of the button ink rgb(83,30,120),0 box 0,0,128,16 rem The pink highlight of the button ink rgb(187,123,237),0 box 0,0,128,1 box 0,0,1,16 rem The dark purple shadow of the button ink rgb(56,9,93),0 box 0,15,128,16 box 128,16,128,0 ink rgb(255,255,255),0 set text font "arial" set text size 10 posx = 64 - (4 * len(caption$)) text posx,1,caption$ get image buttonnum,0,0,129,17 set current bitmap 0 endfunction function makebuttonpressed(caption$,buttonnum) set current bitmap 1 cls 0 rem The light purple body of the button ink rgb(127,22,208),0 box 0,0,128,16 rem The pink highlight of the button ink rgb(187,123,237),0 box 0,15,128,16 box 128,16,128,0 rem The dark purple shadow of the button ink rgb(56,9,93),0 box 0,0,128,1 box 0,0,1,16 ink rgb(255,255,255),0 set text font "arial" set text size 10 posx = 64 - (4 * len(caption$)) text posx,1,caption$ get image buttonnum,0,0,129,17 cls 0 set current bitmap 0 endfunction ` (((((((((((((((((((((((( D A T A )))))))))))))))))))))))))) _months: data "January","February","March","April","May","June" data "July","August","September","October","November","December" ` END OF FILE