User blog:Hseiken/3D Maze Game

Hi, PetitCom/Puchikom fellows. I'll be using this space to update progresson a currently untitled 3D maze exploration game I'm working to put together. Don't get too excited. It's 3D in the same way that Wizardry is 3D. It's still '2D' but with confusing 3D looks to make a simple game much much harder. :)

Here's the latest video showing what has been put in:



Currently, the implemented features are as follows:
 * 32x24 Map Size
 * GPS Mapper Device (Uses PNLSTR to display map on lower screen)
 * Doors
 * Laser EMP Triggers (erases all GPS data up to that point)
 * Infrared Goggles (allows player to see the invisible Laser EMP Sensors
 * Time Limit (when timer reaches 0, life is lost)
 * Lock Picking Minigame (currently is random difficulty from pushover to impossible)
 * Keycards and Keycard-accessed doors (keys and doors correspond specifically)

Some technical information about the program:

The timer system is based on VSYNC/frames. There are 60 frames for each second. Event or loop in the game calls a timer sub. At the start of the program, you find the current number of frames via T=MAINCNTL. From then on, T is reset at the end of the timer sub. You compare the current frames to T. If there's a difference, you add it to a frame counter. When that frame counter = 60, you add a second. Sometimes, however, you will find that drawing the screen or doing an action or what have you will take longer than a frame, so if you go over 60 (remember, you're subtracting the last time frames were looked at to the current frames so it's possible to get values other than 0 or 1!) you have to check for this and adjust accordingly. Here's sample code of the timer subroutine for people's use. I don't see too many people using frames to count time. It has an advantage over system clock (TMREAD(TIME$),HOUR,MIN,SEC) because the system clock doesn't start when you want it to, so your first second will almost always be truncated! As well, there's wonky math keeping track of seconds since, say, your program starts when the system clock is at 34 seconds but you're listing it as 1. It's just ugly and a hastle. So here's that timer code I said I was going to put here like 5 sentences ago: @TIMER​ IF MAINCNTL - T > 0 THEN TICK = TICK + (MAINCNTL - T) IF TICK == 60 THEN SECONDS = SECONDS + 1:TICK = 0 IF TICK > 60 THEN SECONDS = SECONDS + 1:TICK = 60 - TICK And that's pretty much it. As long as you call it fairly regularly, you can use this to make an accurate timer for your game.

So more info about the tech side of things:  Mapping -> drawing! Originally when I started this project, I had intended on the graphics to be completely text-character based, using all those cool little symbols. And it worked, too. Unfortunately, the text layer is not a part of the page flipping (GPAGE) command! So you could see through walls for a split second while the screen updated becuase of the method I used to draw it up (I'll get to that in a second). I'm a big hater of flickering, so I couldn't let that stand so I retraced all the graphics using GLINE, GFILL and GPAINT. Basically, each visible block is it's own subroutine to draw. Even if you can't see it because something closer is in the way, it gets drawn (thus the need to check for extra frames in the timer becaues GPAINT is HELLA slow!). But how does it know where things are in relation to your view? Well, essentially, I load up the map array into a view array a specific way that's entirely dependant on which way you're facing (North, East, South or West). This way, I always load the view array identical each time. Things on the map are are logically further from you go in first and the closest items get loaded in last. This way, we only have to just unload the view array directly into check to see if there's anything there then draw it!

Next the object system is separate from actual map data. The map data consists only of empty, wall or door at the moment and will probably stay that way. Objects have their own arrays (I currently have each object of which there's multiple instances such as keys, special doors, etc. set to 20 because I figured that's plenty to play with in making a level). The object locations are single digit. How I did this was (after I map out a level on graph paper), I take y and multiply it by maximum size of x then add actual x (but taking into account that arrays start at 0...i.e. our map array) so if I have an object at map location x=15, y=8 then actual stored location is (15x31)+8. Each step taken looks at this kind of data then runs down the items list for both if it's viewable and if it's being collected. So, for instance, if the player is standing in front of a door, I already know there's a door there but before I do the standard door action, I use that value to check if it's a lock pick door or a door requiring a key. It's a simple check of running through the array in a loop and comparing it's value with player's location (of course, you have to take into account the door is 1 block in front of them, so you have to check based on direction facing).

For the actual door drawing (since we're on the subject of doors), They are drawn separately from walls. Basically, the drawing goes like this:  Switch to the buffer page (GPAGE). Check for walls then draw them. Check for doors then draw them. Check for special doors and draw on top the special graphics. Check for special items and then draw them. So there's a level of presidence to the items. Even the walls themselves have to be drawn in a specific order so that they don't show up weird. What I mean is...the view is 3 blocks wide. The center block has no 3D, it's just a square due to that thing people call perspective. However, the side 2 blocks connect at the closest face and have inward perspective that if drawn after the center block would overlap it, causing weird looking graphics. So you draw the left block, then the right block, and finally cover up any unwanted perspective graphics with the center block each row at a time. Like I said, it's pretty slow and wasteful, but this isn't needing to be realtime and it's unnoticable when playing (as you can see from the video).

So hopefully that covers some of the stuff people might ask about the program.

My TO DO list is pretty long (programming and planning wise, but not long list wise!) So yeah, it's a lot but not a lot at the same time. A lot of this will just be expanding the framework already there. However, I think the biggest challenge is going to be adding the enemies. That's probably what I'm going to tackle next. After that, everything should be downhill from there (except custom SFX..does someone know how to do this?)
 * Add difficulty levels to lock picking minigame
 * Add 2nd lock picking game (even numbered doors in array will be current game and odd will be new game)
 * Add enemies to main map screen with semi-realtime movement (and logically chasing player based only on line of sight...however I plan on making them not cross items which can be used as a clue for where EMPs are when you don't have goggles)
 * Add health items and tracking
 * Add enemy fight mini game (with likely about 8-12 AI types.  I've already got an idea of how fights will play and it will involve the stylus...I've already moved the action button from the main maze mode to the L BUTTON and will be adding mode for lefties)
 * Add Lefty mode
 * Add title screen
 * Add support for multi-floor levels
 * Add Scoring and special scoring items
 * Add high score and fastest time tables along with save feature for these
 * Add title, intro, instructions and ending screens (probably need a title and disguise the goal in line with the story first!)
 * Add special items that allow avoiding lock picking and enemy fight minigames (corrosives melting off door knobs and long range attack?)
 * Add original music/SFX
 * Add Level Editor with save/load feature
 * Add original campaign (I'm thinking about 30 levels with increasing difficulty and introducing new gameplay elements for the first 15 levels and last 15 levels just play around with the elements to create the difficulty curve up to the final stage)

Hopefully someone finds this blog useful. If anyone wants the current version QR code for study for whatever reason, hit me up. If I give it to you, please don't distribute it as I don't want an unfinished project making the rounds on the internets. :)