Computer Science Canada [Tutorial] Basic Game Programming: Minesweeper, Part 2 |
Author: | DemonWasp [ Thu Jul 23, 2009 12:36 pm ] | ||||||||||||||
Post subject: | [Tutorial] Basic Game Programming: Minesweeper, Part 2 | ||||||||||||||
Prerequisites This is part 2 of the Basic Game Programming tutorial. Part one can be found here, and should be completed before beginning this part. Program Design - Laying the Foundation, Continued We have a bit more to do before we can even start on the game logic (game rules and how to play, etc). For example, even though we have images, we still don't have any way of drawing the map accurately. To do this, let's establish a set of requirements for how we draw the map:
Scaling the Images The requirements imply that we will be required to scale our images before using them. Helpfully, the Pic module built into Turing has a method for just this purpose: Pic.Scale(). This allows us to re-scale images; however, it creates a new image each time, so we should probably do this as rarely as possible. So, we'll do it once right as the program starts, rather than each time we draw the map. The code is relatively straight-forward:
Setting up our Run Window This part is pretty simple and ends up being our very first bit of code:
This tells Turing to set up a window for graphics (rather than text), with a resolution of 800x800 pixels. This window will not display a flashing input cursor, and it won't redraw itself until we call View.Update(). Drawing the Map To draw our map, we will simply "visit" every square of the map, drawing it on the screen as appropriate. This will require two for-loops. We will also wrap the map-drawing up into a procedure so we can refer to it simply; we'll call this procedure draw_map(). I'll separate this into two main parts: drawing the icons for each square of the map, and drawing a set of rulers to neatly separate icons. Drawing the Icons
Drawing the Rulers
Putting it Together
You might wonder why we draw the grid AFTER we draw the icons. Why not draw it first? The reason is because when we draw the images, they would overwrite our rulers, whereas we want our rulers to appear on top of the icons. Clever observers will note that we're missing some possible states in our drawing mechanism here - for example, there's no code for "incorrectly placed flag", represented by the image in pic_flagged_empty. This will come later, as it requires some game logic first. Starting the Game Logic Game logic refers to the game rules and game play. This is what makes the game "Minesweeper" rather than "Battleship", which requires largely the same stuff up until now. Placing the Mines Now that we can draw the map, we need to place some mines on the game board. This is more complicated than it sounds - we need to place a specific number of mines randomly, without putting two mines in one square. We also need to determine the numbers in each square. For our purposes, we'll have one mine for every ten squares in the game. Here's an idea of how we'll do this: 1. For each mine, randomly choose locations until we find one that's empty. 2. Once we've found an empty location, mark the mine there (MAP_MINE) and add one to all the surrounding non-mine squares - this determines the number shown in each square. The code is pretty simple. We'll separate the task into two procedures. The first, place_mines(), does part 1, above. It uses the second, place_mine ( x, y : int ), to do part 2.
Why do I have them in this order (part 2 first, then part 1)? Because the code for part 1 has to be able to call the code for part 2, which means that part 2 must have already been specified before part 1 appears. Getting some Results This is all great, but we still haven't seen anything interesting out of our program! Let's do a little bit of work to get it to draw the map we've worked so hard on...
Running this, we notice that - hooray! - it draws a map with a bunch of mines shown, and the numbers around them are correct! (The mines have exploded because we set every square to be revealed, just as if you'd clicked on it). Next Lesson In the next lesson, we'll start detecting user input (from the mouse) and continue implementing game logic. Users will be able to click to reveal squares and right-click to cycle between flags, question marks, and unmarked. As always, questions, comments and concerns are welcome. You can find the cumulative code from Part 1 and Part 2 attached. |
Author: | chopperdudes [ Thu Jul 23, 2009 6:17 pm ] |
Post subject: | RE:[Tutorial] Basic Game Programming: Minesweeper, Part 2 |
hmm i'm interested to see how you would code the fields. when i made my version (in 2 hours of boredom), i think the most logical (and simple) way to code that would be DFS or BFS. dunno if you'd consider that "basic". |
Author: | DemonWasp [ Thu Jul 23, 2009 6:20 pm ] |
Post subject: | RE:[Tutorial] Basic Game Programming: Minesweeper, Part 2 |
If by "fields" you mean "sections without any mines", then it's actually really easy to do with a really simple recursive procedure that's about 5-10 lines long; we'll be seeing that in either Part 3 or Part 4. |
Author: | chopperdudes [ Thu Jul 23, 2009 6:38 pm ] |
Post subject: | RE:[Tutorial] Basic Game Programming: Minesweeper, Part 2 |
yeah that was what i meant, and yeah with a recursive procedure, like i said perhaps depth first search type, then it'd be short and simple, but originally i thought you weren't gonna use recursion so i was interested to see how you would do it non-recursively. |
Author: | DemonWasp [ Thu Jul 23, 2009 7:10 pm ] |
Post subject: | RE:[Tutorial] Basic Game Programming: Minesweeper, Part 2 |
It can be done without recursion, but it's not as easy. Basically, you end up emulating recursion with a manually-managed stack. The method I've worked up isn't tail-recursive, but if it were it could be refactored into a loop rather than a recursive case. I went with the easiest-possible algorithm for this game: speed is a non-issue, but complexity and algorithmic analysis are largely beyond beginner programmers. |