' Keyboard Capture Code... ' The following codes refer to the machine code for each key on the keyboard. ' By storing these codes into appropriately named constant variables we can ' easily test them without confusion. CONST Key_Up& = 18432 CONST Key_Down& = 20480 CONST Key_Left& = 19200 CONST Key_Right& = 19712 CONST Key_Space& = 32 CONST Key_Enter& = 13 CONST Key_Ctrl& = 100306 CONST Key_Shift& = 100304 CONST Key_KP_Zero& = 48 ' Define a Graphics Type to use when reading records from the .gfx ' files we import. This is optional, you could just draw the graphics ' in game using LINE, CIRLCE and PAINT, etc commands instead, however ' in larger more complex games this will greatly increase the lines of ' code required and extend compile times. TYPE GraphicsType ' Always be descriptive with User Defined Type Names PX AS STRING * 2 ' Pixel X Co-ordinate PY AS STRING * 2 ' Pixel Y Co-ordinate PCO AS STRING * 3 ' Pixel Colour Value END TYPE ' One Image Record (consisting of a value for PX, PY, and PCO) will have a ' length of SEVEN. This value will be assigned to the variable GTIncrement ' and will be used to read the graphics file records sequentially later. DIM SHARED GTIncrement DIM SHARED GT AS GraphicsType ' GT is how we refer to our User Defined Type when opening our files ' Use "SHARED" when dimensioning variables if you plan on having multiple ' SUBS which will test for that value. It is a lot less confusing ' when calling SUBS and will allow for less human error. ' Dimension variable arrays for our graphics. Use a descriptive name for ' example, if the graphic is a Man facing Left then "ManL" would be a good ' name. You can clearly tell what the graphic will be by the name. ' The Number in brackets beside the name refers to how much memory the graphic ' will require. Below is a reference for the graphics used in this game... ' 10 x 10 pixels = (51) ' 20 x 20 pixels = (201) ' 30 x 30 pixels = (451) ' 40 x 40 pixels = (801) ' The formula is as follows - Width x Height (in pixels) / 2 + 1 ' Use this formula rather than guessing the numbers. Having large numbers ' in excess of what is required will waste memory. ' These are the Graphic Arrays for our Character. There are 22 frames in ' total. This is just an example, you could quite easily use more or less ' frames in your own animations. DIM SHARED ManL(801) AS INTEGER ' Standing, Walking and Crouching DIM SHARED ManLStep(801) AS INTEGER DIM SHARED ManLCrouch(801) AS INTEGER DIM SHARED ManLfi8(801) AS INTEGER ' Firing the Shotgun DIM SHARED ManLfi7(801) AS INTEGER DIM SHARED ManLfi6(801) AS INTEGER DIM SHARED ManLfi5(801) AS INTEGER DIM SHARED ManLCfi8(801) AS INTEGER ' Firing while crouching DIM SHARED ManLCfi7(801) AS INTEGER DIM SHARED ManLCfi6(801) AS INTEGER DIM SHARED ManLCfi5(801) AS INTEGER DIM SHARED ManR(801) AS INTEGER ' These are the same but facing right DIM SHARED ManRStep(801) AS INTEGER DIM SHARED ManRCrouch(801) AS INTEGER DIM SHARED ManRfi8(801) AS INTEGER DIM SHARED ManRfi7(801) AS INTEGER DIM SHARED ManRfi6(801) AS INTEGER DIM SHARED ManRfi5(801) AS INTEGER DIM SHARED ManRCfi8(801) AS INTEGER DIM SHARED ManRCfi7(801) AS INTEGER DIM SHARED ManRCfi6(801) AS INTEGER DIM SHARED ManRCfi5(801) AS INTEGER ' The door has a closed and open state, comprised of three images DIM SHARED DoorBottom(801) AS INTEGER DIM SHARED DoorTop(51) AS INTEGER DIM SHARED DoorOpen(51) AS INTEGER ' Grass is a Decal Image used to make the floors look more interesting. DIM SHARED Grass(201) AS INTEGER ' The Droid is going to move around the screen switching from left to right. DIM SHARED DroidLeft(201) AS INTEGER DIM SHARED DroidRight(201) AS INTEGER ' Crates will be placed on the screen for effect. DIM SHARED CrateWood(451) AS INTEGER ' These Rock Decals will be placed as foreground objects. DIM SHARED RockDecalBottom(451) AS INTEGER DIM SHARED RockDecalBottom1(451) AS INTEGER DIM SHARED RockDecalTop(451) AS INTEGER DIM SHARED RockDecalTop1(451) AS INTEGER ' These hearts form the health meter in the HUD. DIM SHARED SmallHeart(201) AS INTEGER DIM SHARED SmallHeart1(201) AS INTEGER DIM SHARED HalfHeart(201) AS INTEGER DIM SHARED HalfHeart1(201) AS INTEGER ' The Get Images SUB routine will capture our images and store them in the ' image arrays we defined earlier. DECLARE SUB GetImages ' The DrawImages SUB routine will be used to draw graphics onto the screen at ' different points during the game loop. The DrawWhat variable will define ' what to draw when the routine is called. It has been Dimensioned as a ' STRING so we can clearly see what to draw. It's values are as follows: ' "BackGround" - Draw the Background Tiles Only ' "FixedSprites" - Draw things that are fixed in position but not background objects ' "MovingSprites" - Draw Enemies and other items that change position ' "ForeGround" - Draw Decals in front of everything else DECLARE SUB DrawImages DIM SHARED DrawWhat AS STRING ' This SUB routine draws the Heads Up Display DECLARE SUB Hud ' GameTimer is a variable used to control fast animations. In our example it ' will range from -16 to 16 but could be altered to suit your needs. DIM SHARED GameTimer ' TimeCount measures One Second Delays. Our example will increment until it ' reaches 4 and then reset to 0. DIM SHARED TimeCount ' Secs (Seconds) and Mins (Minutes) will be used to make our level timer. DIM SHARED Secs, Mins ' The DrawMan SUB routine will draw the man :| . All Man variables are ' pre-fixed with with "Mn" so that we can tell them apart from other variables. DECLARE SUB DrawMan DIM SHARED MnX, MnY, MnSide ' X and Y Position and the direction he is facing DIM SHARED MnWalkOn, MnWalkTimer, MnCrouchOn, MnJumpOn ' Movement Status DIM SHARED MnFireTimer, MnFireOn ' Firing Status. DIM SHARED MnHealth, MnAmmo ' Health and Ammunition Status Variables ' Every object in the game (excluding the man) will be loaded in the form of ' a tile. ' Each Tile has several properties which will tell our DrawImages SUB routine ' how to draw the tile and also which tiles can be interacted with by the ' player. There are currently 30 tiles per screen, this can be modified. DIM SHARED TileType(30) DIM SHARED TileProperty1(30) DIM SHARED TileProperty2(30) DIM SHARED TileColour1(30) DIM SHARED TileColour2(30) DIM SHARED TileX1(30) DIM SHARED TileY1(30) DIM SHARED TileX2(30) DIM SHARED TileY2(30) ' Always include an Error Handler in your programs even if it does just end ' the program. That's far better than it catching an exception and scaring ' the user into thinking they have crashed their machine. ON ERROR GOTO Errors ' Here we call the GetImages SUB routine which will load all the game images ' we require for use throughout the game. GTIncrement = 7 ' The length of our Graphics Type (defined at the beggining) GetImages Start: ' Set up Game Variables ' Health MnHealth = 290 ' 315 = dead / 275 = full, increment -5 for half a heart ' Ammunition MnAmmo = 60 ' 90 = full / 0 = empty, increment 3 for one shell ' Timers GameTimer = -1 ' GameTimer can never equal zero or the animations will freeze TimeCount = 1 ' Reset all 30 tiles to -1 values (don't exist) before we modify them. FOR ResetTile = 0 TO 29 TileType(ResetTile) = -1 TileProperty1(ResetTile) = -1 TileProperty2(ResetTile) = -1 TileColour1(ResetTile) = -1 TileColour2(ResetTile) = -1 TileX1(ResetTile) = -1 TileY1(ResetTile) = -1 TileX2(ResetTile) = -1 TileY2(ResetTile) = -1 NEXT ResetTile ' Call the gsGetTiles GOSUB routine to create the game objects. GOSUB gsGetTiles ' Place our Man into the level and give him health and ammunition MnX = 60 MnY = 50 MnSide = 1 MnHealth = 270 MnAmmo = 60 ' Set OrigTime$ Variable to the current system time (TIME$). OrigTime$ = TIME$ ' The following variable TimeSet will determine how fast the game runs. Play ' around with it and see what happens. TimeSet = 1 ' Reset this variable to 0. It needs to equal TimeSet in order for the game ' loop to process. It will be incremented by 1 at the end of the main game ' loop. GameSpeed = 0 DO ' Clear a space in memory to store the timer ticks using DEF SEG. DEF SEG = 0 ' Reset the Timer Tick to 0 using POKE. POKE 1132, 0 ' Draw the Background, Floors and Walls Only... DrawWhat$ = "BackGround" DrawImages ' Now that we have tested for collisions we can draw the more complex ' images onto the screen starting with the Fixed Sprites... DrawWhat$ = "FixedSprites" DrawImages ' Now we can draw the interactive sprites. DrawWhat$ = "MovingSprites" DrawImages ' The foreground images are placed in front of the man, aswell as the HUD DrawWhat$ = "ForeGround" DrawImages ' If the desired delay has passed then process the main game loop... IF GameSpeed = TimeSet THEN ' Clear the Keyboard buffer and end game if escape key is pressed FOR KbdLoop = 0 TO 32 ' The buffer remembers only 32 keystrokes. Kbd$ = "" ' Reset Kbd$ to nothing so that it can be reused. ' By setting Kbd$ to INKEY$ we take one keystroke away from the keyboard ' buffer, once we have done this 32 times the buffer will be empty. Kbd$ = INKEY$ IF Kbd$ = CHR$(27) THEN ' CHR$(27) is the character code for 'Escape' ' Clear the screen then display the blank screen, pause for a moment ' and disable full screen mode, then return to the OS. CLS _DISPLAY SLEEP 1 _FULLSCREEN _OFF SYSTEM END IF NEXT KbdLoop ' Increment the GameTimer Variable IF GameTimer > 0 THEN GameTimer = GameTimer + 1 IF GameTimer < 0 THEN GameTimer = GameTimer - 1 ' Reset the GameTimer Variable if it gets to large. 16 works quite well ' but can be changed to suit longer or shorter animation requirements. IF GameTimer < -16 THEN GameTimer = 1 ELSEIF GameTimer > 16 THEN GameTimer = -1 END IF ' Increment TimeCount if one second has passed and calculate the seconds ' and minutes that have passed since beginning the game. Note that if the ' time goes passed midnight it will reset to 0:00:00 and the calculations ' wont work which will stop the animations also. There is a fix for this, ' it's so infrequent that I never bothered with it. IF TIME$ > OrigTime$ THEN TimeCount = TimeCount + 1 ' Reset OrigTime so we can wait for another second to pass OrigTime$ = TIME$ ' If we reach 10 minutes then stop counting... IF NOT (Mins = 9 AND Secs = 59) THEN Secs = Secs + 1 ' After a minute, reset seconds to zero and increment minutes by one. IF Secs = 60 THEN Secs = 0 Mins = Mins + 1 END IF END IF ' TimeCount can be reset at any stage, but in this example we will use 4. ' 4 means you can have 4 one second animations (eg an item spinning around ' using 4 animations will end up back where it started when we reset ' TimeCount). IF TimeCount = 4 THEN OrigTime$ = TIME$ TimeCount = 0 END IF ' Reset this variable in order to maintain a constant game speed. If you ' don't the game will display once and then freeze :( GameSpeed = 0 ' Having the _DISPLAY command inside a loop disables the auto display ' which happens as standard. This means that nothing that we have drawn ' onto the screen has been displayed so far, its all been drawn into ' memory, ready to be copied to the screen once the loop reaches this ' command. _DISPLAY END IF ' Once we have completed one cycle of the main game loop we must then pause ' until the clock ticks have reached aproximately 1/18th of a second since ' we started the loop (this is how we maintain the speed, we are testing ' an external time source instead of variables within the game). DO ' Delay for 1/18th of a second LOOP UNTIL PEEK(1132) >= 1 DEF SEG ' reset segment to default ' GameSpeed is incremented and then tested at the beginning of the loop. GameSpeed = GameSpeed + 1 LOOP Errors: ' Using SYSTEM instead of END will return the user to the OS without having to ' press any key to continue. SYSTEM gsGetTiles: ' Normally in larger games you would read these values from a level file of ' some sort rather than create them in code, however for this example we only ' have one screen to display so we will just create each tile manually. ' To do this we need to define a Type, some Properties, Colours and Position ' for each tile so that the DrawImages SUB routine can arrange them on the ' screen appropriately. ' Create a floor tile with straight sides, in two shades of brown, starting ' from x(-20), y(180) and finishing at x(339), y(199). TileType(0) = 0 ' 0 for Floor TileProperty1(0) = 0 ' 0 for Straight edges TileColour1(0) = 6 ' 6 for Standard Brown Colour TileColour2(0) = 42 ' 42 for Light Brown Colour TileX1(0) = -20 ' The Co-ordinates from above TileY1(0) = 180 TileX2(0) = 339 TileY2(0) = 199 ' There, done, the first tile has been created, now to make some more floors TileType(1) = 0 ' 0 for Floor TileProperty1(1) = 2 ' 2 for Slanted edges TileColour1(1) = 6 ' 6 for Standard Brown Colour TileColour2(1) = 42 ' 42 for Light Brown Colour TileX1(1) = -20 ' In the middle on the left hand side TileY1(1) = 90 TileX2(1) = 119 TileY2(1) = 109 TileType(2) = 0 ' 0 for Floor TileProperty1(2) = 2 ' 2 for Slanted edges TileColour1(2) = 6 ' 6 for Standard Brown Colour TileColour2(2) = 42 ' 42 for Light Brown Colour TileX1(2) = 200 ' In the middle on the Right hand side TileY1(2) = 90 TileX2(2) = 339 TileY2(2) = 109 TileType(3) = 0 ' 0 for Floor TileProperty1(3) = 0 ' 0 for Straight edges TileColour1(3) = 6 ' 6 for Standard Brown Colour TileColour2(3) = 42 ' 42 for Light Brown Colour TileX1(3) = -20 ' A roof for the room TileY1(3) = 0 TileX2(3) = 339 TileY2(3) = 19 ' Now for some walls... TileType(4) = 1 ' 1 for Wall TileProperty1(4) = 2 ' 2 for Slanted edges TileColour1(4) = 6 ' 6 for Standard Brown Colour TileColour2(4) = 42 ' 42 for Light Brown Colour TileX1(4) = -20 ' Top Left Hand Side TileY1(4) = 20 TileX2(4) = 39 TileY2(4) = 89 TileType(5) = 1 ' 1 for Wall TileProperty1(5) = 1 ' 1 for Rounded edges TileColour1(5) = 6 ' 6 for Standard Brown Colour TileColour2(5) = 42 ' 42 for Light Brown Colour TileX1(5) = 280 ' Bottom Right Hand Side TileY1(5) = 110 TileX2(5) = 339 TileY2(5) = 179 TileType(6) = 1 ' 1 for Wall TileProperty1(6) = 1 ' 1 for Rounded edges TileColour1(6) = 6 ' 6 for Standard Brown Colour TileColour2(6) = 42 ' 42 for Light Brown Colour TileX1(6) = 220 ' Bottom Right Hand Cieling TileY1(6) = 110 TileX2(6) = 299 TileY2(6) = 129 TileType(7) = 1 ' 1 for Wall TileProperty1(7) = 1 ' 1 for Rounded edges TileColour1(7) = 6 ' 6 for Standard Brown Colour TileColour2(7) = 42 ' 42 for Light Brown Colour TileX1(7) = 20 ' Top Left Hand Cieling TileY1(7) = 20 TileX2(7) = 99 TileY2(7) = 39 ' And now some Droids... TileType(8) = 14 ' 14 for Droid TileProperty1(8) = 10 ' 10 hit points TileProperty2(8) = 0 ' 0 to spawn facing left TileX1(8) = 60 ' Bottom Floor TileY1(8) = 160 TileX2(8) = 79 TileY2(8) = 179 TileType(9) = 14 ' 14 for Droid TileProperty1(9) = 10 ' 10 hit points TileProperty2(9) = 1 ' 1 to spawn facing right TileX1(9) = 160 ' Bottom Floor TileY1(9) = 160 TileX2(9) = 179 TileY2(9) = 179 ' And a Crate or two for good luck... TileType(10) = 15 ' 15 for Crate TileProperty1(10) = 10 ' 10 hit points TileProperty2(10) = 0 ' 0 to spawn as a wooden crate TileX1(10) = 240 ' Bottom Floor TileY1(10) = 150 TileX2(10) = 279 TileY2(10) = 179 TileType(11) = 15 ' 15 for Crate TileProperty1(11) = 10 ' 10 hit points TileProperty2(11) = 0 ' 0 to spawn as a wooden crate TileX1(11) = 205 ' Bottom Floor TileY1(11) = 150 TileX2(11) = 234 TileY2(11) = 179 ' For instant awesome, just add rocks... TileType(12) = 16 ' 16 for Decal TileProperty1(12) = 2 ' 2 for Rocks TileProperty2(12) = 0 ' 0 for Bottom Left Side TileX1(12) = 20 ' Bottom Floor TileY1(12) = 155 TileX2(12) = 49 TileY2(12) = 184 TileType(13) = 16 ' 16 for Decal TileProperty1(13) = 2 ' 2 for Rocks TileProperty2(13) = 1 ' 1 for Bottom Right Side TileX1(13) = 255 ' Bottom Floor TileY1(13) = 155 TileX2(13) = 284 TileY2(13) = 184 TileType(14) = 16 ' 16 for Decal TileProperty1(14) = 2 ' 2 for Rocks TileProperty2(14) = 2 ' 2 for Top Left Side TileX1(14) = 35 ' Top Floor TileY1(14) = 35 TileX2(14) = 64 TileY2(14) = 64 TileType(15) = 16 ' 16 for Decal TileProperty1(15) = 2 ' 2 for Rocks TileProperty2(15) = 0 ' 0 for Bottom Left Side TileX1(15) = 30 ' Top Floor TileY1(15) = 65 TileX2(15) = 59 TileY2(15) = 94 ' And a door to finish things off... TileType(16) = 2 ' 2 for Door TileProperty1(16) = 0 ' 0 for Unlocked TileColour1(16) = 6 ' 6 for Standard Brown Colour TileColour2(16) = 42 ' 42 for Light Brown Colour TileX1(16) = 220 ' Top Floor TileY1(16) = 20 TileX2(16) = 239 TileY2(16) = 89 ' If you are wondering why the tile type numbers are out of order its because ' the tile definitions are ripped straight from another game of mine and I'm ' only using a few of the available tiles in this demo to show the basic ' method of level building. RETURN SUB GetImages ' This SUB routine converts the .gfx (text) files into images and stores them ' into easily called upon variable arrays. ' Set the screen dimensions and colours. the ", , 1, 0" uses screen page 1 ' instead of the default 0 meaning we will not see any drawing on the screen ' until we switch screen pages. This looks much more professional than having ' a bunch of images flash up on the screen and disappear suddenly. ' In this example we are using a screen mode identical to the old Qbasic ' Screen Mode 13. 320 pixels wide x 200 pixels high and with 256 colours. The ' difference is that we can use a screen page in QB64 where that was not ' possible in the original Qbasic program. SCREEN _NEWIMAGE(320, 200, 256), , 1, 0 ' This sets the window to full screen mode, comment out if you prefer a ' normal window instead. _FULLSCREEN ' This part of the SUB opens each individual Image file one by one, draws it ' on the screen, then captures it and stores it as a variable array. Broken ' down it works like this... ' Open the File we need located in the Resources Directory and read each ' record using the length defined by GT. OPEN "Resources\ManL.gfx" FOR BINARY AS 1 LEN = LEN(GT) ' Run the GetLoop GOSUB procedure to read the file and draw its contents ' onto the screen. GOSUB GetLoop ' Use the graphics statement "GET" to capture the displayed image and store it ' in the matching variable array. (0, 0)-(39, 39) captures an image 40 pixels ' wide by 40 pixels high. This will change depending on the image. GET (0, 0)-(39, 39), ManL() ' Close the file so that we can open another. CLOSE #1 ' Now repeat this for all remaining images. OPEN "Resources\ManLStep.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLStep() CLOSE #1 OPEN "Resources\ManLCrouch.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLCrouch() CLOSE #1 OPEN "Resources\ManLfi8.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLfi8() CLOSE #1 OPEN "Resources\ManLfi7.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLfi7() CLOSE #1 OPEN "Resources\ManLfi6.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLfi6() CLOSE #1 OPEN "Resources\ManLfi5.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLfi5() CLOSE #1 OPEN "Resources\ManLCfi8.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLCfi8() CLOSE #1 OPEN "Resources\ManLCfi7.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLCfi7() CLOSE #1 OPEN "Resources\ManLCfi6.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLCfi6() CLOSE #1 OPEN "Resources\ManLCfi5.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManLCfi5() CLOSE #1 OPEN "Resources\ManR.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManR() CLOSE #1 OPEN "Resources\ManRStep.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRStep() CLOSE #1 OPEN "Resources\ManRCrouch.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRCrouch() CLOSE #1 OPEN "Resources\ManRfi8.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRfi8() CLOSE #1 OPEN "Resources\ManRfi7.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRfi7() CLOSE #1 OPEN "Resources\ManRfi6.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRfi6() CLOSE #1 OPEN "Resources\ManRfi5.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRfi5() CLOSE #1 OPEN "Resources\ManRCfi8.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRCfi8() CLOSE #1 OPEN "Resources\ManRCfi7.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRCfi7() CLOSE #1 OPEN "Resources\ManRCfi6.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRCfi6() CLOSE #1 OPEN "Resources\ManRCfi5.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), ManRCfi5() CLOSE #1 OPEN "Resources\Grass.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), Grass() CLOSE #1 OPEN "Resources\DroidLeft.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), DroidLeft() CLOSE #1 OPEN "Resources\DroidRight.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), DroidRight() CLOSE #1 OPEN "Resources\RockDecalBottom.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(29, 29), RockDecalBottom() CLOSE #1 OPEN "Resources\RockDecalBottom1.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(29, 29), RockDecalBottom1() CLOSE #1 OPEN "Resources\RockDecalTop.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(29, 29), RockDecalTop() CLOSE #1 OPEN "Resources\RockDecalTop1.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(29, 29), RockDecalTop1() CLOSE #1 OPEN "Resources\SmallHeart.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), SmallHeart() CLOSE #1 OPEN "Resources\SmallHeart1.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), SmallHeart1() CLOSE #1 OPEN "Resources\HalfHeart.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), HalfHeart() CLOSE #1 OPEN "Resources\HalfHeart1.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(19, 19), HalfHeart1() CLOSE #1 OPEN "Resources\CrateWood.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(29, 29), CrateWood() CLOSE #1 OPEN "Resources\DoorBottom.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(39, 39), DoorBottom() CLOSE #1 OPEN "Resources\DoorTop.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(9, 9), DoorTop() CLOSE #1 OPEN "Resources\DoorOpen.gfx" FOR BINARY AS 1 LEN = LEN(GT) GOSUB GetLoop GET (0, 0)-(9, 9), DoorOpen() CLOSE #1 ' Now that we are finished we can switch screen pages and start drawing to the ' screen in the main game loop and exit the SUB routine. SCREEN _NEWIMAGE(320, 200, 256), , 0, 0 EXIT SUB GetLoop: ' This looks trickier than it is... ' First we find the end of the file and store it as LoopIncrement LoopIncrement = LOF(1) ' LOF stands for Last of File and 1 is our open file. ' Now we read the last record (End of File, - 1 Record Length, + 1) GET #1, LoopIncrement - GTIncrement + 1, GT ' Work out how large the image is by reading the last X and Y Co-Ordinates PointX = VAL(GT.PX) PointY = VAL(GT.PY) ' LoopIncrement is set to -GTIncrement so that when the loop starts and ' GTIncrement is added back in, the records will start at 0. LoopIncrement = -GTIncrement ' This loop starts at co-ordinate 0, 0 and works its way to 39, 39 (in the ' first case). PointX and PointY were determined earlier. FOR DrawY = 0 TO PointY FOR DrawX = 0 TO PointX ' Read the current record values GET #1, LoopIncrement + GTIncrement + 1, GT ' We are only interested in the colour value which we will set to PointCo. ' We need to use the VAL function because GT.PCO is a STRING and we need ' to convert it to an INTEGER. PointCo = VAL(GT.PCO) ' Now that we have an X, Y and Colour value we can draw the pixel on the ' screen using PSET. PSET (DrawX, DrawY), PointCo ' We now increase LoopIncrement by GTIncrement to move to the next record ' and continue looping until the last pixel is drawn. LoopIncrement = LoopIncrement + GTIncrement NEXT DrawX NEXT DrawY ' The image is now printed in full and can be captured by the GET command back ' in the GetImages main program code... RETURN END SUB SUB DrawImages ' Notice that any PUT graphics statements use the _CLIP parameter and have ' an ", 8" at the end. _CLIP means the image can be placed off the screen and ' the eight at the end turns any pixel in the image with a colour value of ' 8 (Grey, same as background) into an invisible pixel for transperancy. IF DrawWhat$ = "BackGround" THEN ' Draw Background objects only... LINE (0, 0)-(319, 199), 8, BF ' Colour the background Grey ' Cycle through the pre-defined tiles using DrawTile as an index... FOR DrawTile = 0 TO 29 IF TileType(DrawTile) = 0 THEN GOSUB gsDrawFloor IF TileType(DrawTile) = 1 THEN GOSUB gsDrawWall IF TileType(DrawTile) = 2 THEN GOSUB gsDrawDoor IF TileType(DrawTile) = 15 THEN GOSUB gsDrawCrate NEXT DrawTile ' Search for green lines on the floors and place the grass image when detected GrassY = 90 FOR GrassX = 0 TO 300 STEP 20 GrassPoint = POINT(GrassX + 1, GrassY + 1) ' Top Floor IF GrassPoint = 2 THEN PUT (GrassX, GrassY), Grass(), _CLIP PSET, 8 GrassPoint = POINT(GrassX + 1, GrassY + 91) ' Bottom Floor IF GrassPoint = 2 THEN PUT (GrassX, GrassY + 90), Grass(), _CLIP PSET, 8 NEXT GrassX ELSEIF DrawWhat$ = "FixedSprites" THEN ' Draw Fixed Sprites Only... ' Nothing here now, but you could put things like switches, teleports, etc ELSEIF DrawWhat$ = "MovingSprites" THEN ' Draw Moving Sprites Only... FOR DrawTile = 0 TO 29 IF TileType(DrawTile) = 14 THEN GOSUB gsDrawDroid ' Draw the Droids NEXT DrawTile ELSE ' Draw the Decals... FOR DrawTile = 0 TO 29 IF TileType(DrawTile) = 16 THEN GOSUB gsDrawDecal ' Draw the Rocks... NEXT DrawTile END IF EXIT SUB gsDrawFloor: ' This routine basically reads the tile properties and draws a floor to match. ' The code is taken straight from another game file of mine and some parts ' are not needed here but you can play around and see what you get... LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY1(DrawTile)), 0 SELECT CASE TileProperty1(DrawTile) ' What type of edges does it have? CASE 0 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile)), 0 LINE (TileX1(DrawTile), TileY2(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile)), 0 CASE 1 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile) - 5), 0 LINE (TileX1(DrawTile), TileY2(DrawTile) - 5)-(TileX1(DrawTile) + 5, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 5, TileY2(DrawTile))-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY2(DrawTile) - 5)-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile) - 5), 0 CASE 2 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile) + 5, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 5, TileY2(DrawTile))-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile) - 5, TileY2(DrawTile))-(TileX2(DrawTile), TileY1(DrawTile)), 0 CASE 3 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile) - 5), 0 LINE (TileX1(DrawTile), TileY2(DrawTile) - 5)-(TileX1(DrawTile) + 10, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 10, TileY2(DrawTile))-(TileX2(DrawTile) - 10, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY2(DrawTile) - 5)-(TileX2(DrawTile) - 10, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile) - 5), 0 END SELECT IF TileX1(DrawTile) < 0 THEN PAINT (TileX1(DrawTile) + 20, TileY1(DrawTile) + 1), TileColour1(DrawTile), 0 IF TileX1(DrawTile) >= 0 THEN PAINT (TileX1(DrawTile) + 2, TileY1(DrawTile) + 1), TileColour1(DrawTile), 0 IF NOT TileX1(DrawTile) > TileX2(DrawTile) - 20 THEN LINE (TileX1(DrawTile) + 20, TileY1(DrawTile) + 1)-(TileX2(DrawTile) - 20, TileY1(DrawTile) + 9), TileColour2(DrawTile), BF IF TileY1(DrawTile) = 0 THEN GOTO RoofTile ' No Grass on the roof... IF TileColour1(DrawTile) = 4 THEN DrawCo1 = 112 DrawCo2 = 184 END IF IF TileColour1(DrawTile) = 6 THEN DrawCo1 = 2 DrawCo2 = 120 END IF IF TileColour1(DrawTile) > 15 AND TileColour1(DrawTile) < 25 THEN DrawCo1 = 43 DrawCo2 = 6 END IF IF TileColour1(DrawTile) > 24 AND TileColour1(DrawTile) < 32 THEN DrawCo1 = 44 DrawCo2 = 42 END IF IF TileColour1(DrawTile) = 115 THEN DrawCo1 = 42 DrawCo2 = 6 END IF IF TileColour1(DrawTile) = 53 THEN DrawCo1 = 15 DrawCo2 = 7 END IF IF TileColour1(DrawTile) = 56 THEN DrawCo1 = 48 DrawCo2 = 10 END IF LINE (TileX1(DrawTile), TileY1(DrawTile) + 1)-(TileX2(DrawTile), TileY1(DrawTile) + 1), DrawCo1 LINE (TileX1(DrawTile), TileY1(DrawTile) + 2)-(TileX2(DrawTile), TileY1(DrawTile) + 2), DrawCo2 RoofTile: ' Don't draw grass on the roof... RETURN gsDrawWall: ' This routine basically reads the tile properties and draws a Wall to match. ' The code is taken straight from another game file of mine and some parts ' are not needed here but you can play around and see what you get... LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY1(DrawTile)), 0 LINE (TileX1(DrawTile) + 10, TileY1(DrawTile) + 1)-(TileX2(DrawTile) - 10, TileY2(DrawTile) - 1), TileColour1(DrawTile), BF SELECT CASE TileProperty1(DrawTile) ' What type of edges does it have? CASE 0 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile)), 0 LINE (TileX1(DrawTile), TileY2(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile)), 0 CASE 1 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile) - 5), 0 LINE (TileX1(DrawTile), TileY2(DrawTile) - 5)-(TileX1(DrawTile) + 5, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 5, TileY2(DrawTile))-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY2(DrawTile) - 5)-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile) - 5), 0 CASE 2 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile) + 5, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 5, TileY2(DrawTile))-(TileX2(DrawTile) - 5, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile) - 5, TileY2(DrawTile))-(TileX2(DrawTile), TileY1(DrawTile)), 0 CASE 3 LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile), TileY2(DrawTile) - 5), 0 LINE (TileX1(DrawTile), TileY2(DrawTile) - 5)-(TileX1(DrawTile) + 10, TileY2(DrawTile)), 0 LINE (TileX1(DrawTile) + 10, TileY2(DrawTile))-(TileX2(DrawTile) - 10, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY2(DrawTile) - 5)-(TileX2(DrawTile) - 10, TileY2(DrawTile)), 0 LINE (TileX2(DrawTile), TileY1(DrawTile))-(TileX2(DrawTile), TileY2(DrawTile) - 5), 0 END SELECT IF TileX1(DrawTile) < 0 THEN PAINT (TileX1(DrawTile) + 20, TileY1(DrawTile) + 1), TileColour1(DrawTile), 0 IF TileX1(DrawTile) >= 0 THEN PAINT (TileX1(DrawTile) + 2, TileY1(DrawTile) + 1), TileColour1(DrawTile), 0 LINE (TileX1(DrawTile) + 1, TileY1(DrawTile))-(TileX2(DrawTile) - 1, TileY1(DrawTile)), TileColour1(DrawTile) LINE (TileX1(DrawTile) + 10, TileY1(DrawTile) + 1)-(TileX2(DrawTile) - 10, TileY2(DrawTile) - 10), TileColour2(DrawTile), BF RETURN gsDrawDoor: ' This routine draws the door either open or closed, locked or unlocked, etc LINE (TileX1(DrawTile), TileY1(DrawTile))-(TileX1(DrawTile) + 19, TileY1(DrawTile) + 19), 0, B LINE (TileX1(DrawTile) + 1, TileY1(DrawTile) - 1)-(TileX1(DrawTile) + 18, TileY1(DrawTile) + 18), TileColour1(DrawTile), BF LINE (TileX1(DrawTile) + 5, TileY1(DrawTile) - 10)-(TileX1(DrawTile) + 14, TileY1(DrawTile) + 9), TileColour2(DrawTile), BF PSET (TileX1(DrawTile), TileY1(DrawTile) + 19), 20 PSET (TileX2(DrawTile), TileY1(DrawTile) + 19), 20 ' If the door is unlocked and the man is standing under it then draw it open. IF MnY > TileY1(DrawTile) AND MnY < TileY2(DrawTile) AND MnX >= TileX1(DrawTile) - 25 AND MnX <= TileX2(DrawTile) + 26 AND TileProperty1(DrawTile) = 0 THEN PUT (TileX1(DrawTile) + 5, TileY1(DrawTile) + 20), DoorOpen(), _CLIP PSET, 8 ELSE PUT (TileX1(DrawTile) + 5, TileY1(DrawTile) + 30), DoorBottom(), _CLIP PSET, 8 PUT (TileX1(DrawTile) + 5, TileY1(DrawTile) + 20), DoorTop(), _CLIP PSET, 8 IF TileProperty1(DrawTile) = 0 THEN IF TimeCount = 1 OR TimeCount = 3 THEN LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 39)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 50), 192, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 41)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 48), 120, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 43)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 46), 2, B END IF ELSE IF TimeCount = 1 OR TimeCount = 3 THEN ' Make the light flash once per second LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 39)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 50), 112, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 41)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 48), 4, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 43)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 46), 40, B ELSE LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 39)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 50), 184, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 41)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 48), 112, B LINE (TileX1(DrawTile) + 9, TileY1(DrawTile) + 43)-(TileX1(DrawTile) + 10, TileY1(DrawTile) + 46), 4, B END IF END IF END IF RETURN gsDrawDroid: ' This routine draws and moves the droids, they bounce up and down based on ' the GameTimer value, whether it is negative or positive. IF TileProperty1(DrawTile) > 0 THEN IF TileProperty2(DrawTile) = 0 THEN DroidTest = POINT(TileX1(DrawTile) - 1, TileY2(DrawTile) + 1) IF DroidTest <> 0 THEN TileProperty2(DrawTile) = 1 DroidTest = POINT(TileX1(DrawTile) - 1, TileY1(DrawTile) + 1) IF DroidTest <> 8 THEN TileProperty2(DrawTile) = 1 TileX1(DrawTile) = TileX1(DrawTile) - 1 TileX2(DrawTile) = TileX2(DrawTile) - 1 IF GameTimer > 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), DroidLeft(), _CLIP PSET, 8 IF GameTimer < 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile) + 1), DroidLeft(), _CLIP PSET, 8 ELSE DroidTest = POINT(TileX2(DrawTile) + 1, TileY2(DrawTile) + 1) IF DroidTest <> 0 THEN TileProperty2(DrawTile) = 0 DroidTest = POINT(TileX2(DrawTile) + 1, TileY1(DrawTile) + 1) IF DroidTest <> 8 THEN TileProperty2(DrawTile) = 0 TileX1(DrawTile) = TileX1(DrawTile) + 1 TileX2(DrawTile) = TileX2(DrawTile) + 1 IF GameTimer > 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), DroidRight(), _CLIP PSET, 8 IF GameTimer < 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile) + 1), DroidRight(), _CLIP PSET, 8 END IF END IF RETURN gsDrawCrate: ' Put a wooden crate on the screen somewhere... IF TileProperty1(DrawTile) > 0 THEN IF TileProperty2(DrawTile) = 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile) + 1), CrateWood(), _CLIP PSET, 8 END IF RETURN gsDrawDecal: ' Draw some rocks... SELECT CASE TileProperty1(DrawTile) CASE 2 IF TileProperty2(DrawTile) = 0 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), RockDecalBottom(), _CLIP PSET, 8 IF TileProperty2(DrawTile) = 1 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), RockDecalBottom1(), _CLIP PSET, 8 IF TileProperty2(DrawTile) = 2 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), RockDecalTop(), _CLIP PSET, 8 IF TileProperty2(DrawTile) = 3 THEN PUT (TileX1(DrawTile), TileY1(DrawTile)), RockDecalTop1(), _CLIP PSET, 8 END SELECT RETURN END SUB