cgrooves / black-earth

A Scorched Earth clone, made for fun
2 stars 2 forks source link

Cgrooves/issue9 #14

Closed cgrooves closed 3 years ago

cgrooves commented 3 years ago

Overview

This pull request implements the switching logic between controlling multiple tanks, and allows you to initialize the game with a variable number of tanks.

Why the branch off of cgrooves/issue5 instead of main?

I created this branch using the existing issue5 branch (which was completed with #12 ), in order to have the code for creating and controlling a tank as a jumping off point while #12 was still being reviewed and resolved. Generally, this is not recommended (i.e. making a branch off of something that's not main), but sometimes it is necessary. Whenever you can, it's better to branch off of main and bring in updates to main as you go (i.e. git fetch; git merge remotes/origin/main).

Why so simple?

The main objective of this pull request was to update the game logic so that you can "take turns" moving the tank turret angle. I intentionally did NOT make "shooting" a part of this, and that is simply to keep things short and sweet. A couple of extra things crept their way into the pull request, and that's okay, because they go along nicely with the objective of these issues and were kind of a "figured out along the way" thing rather than a "trying to dual focus".

Why Tank is a module

The reason that I stuck the Tank class into its own module is simply to try and keep things cleaner in the main file, and to support the idea of extensibility in the future. We may (in fact, definitely will) have different types of tanks. It makes sense to put definitions of those tanks (e.g. what they look like, how they're controlled, etc.) off into their own file, maybe even their own package. That's looking a little too far ahead. For now, the main point is that if you're trying to understand what the main game is, you want to be able to digest it one block at a time. Here's a bit of an internal conversation that I hope would be encouraged by this structuring decision:

What is this game, and how does it work? Let me open up the main blackearth.py file and take a look. Ok, there's a main window here, that's spiffy, and it looks like it creates a bunch of Tank objects. Oh, and it has some part here for handling key press and release events, and drawing and updating, _and it looks like the Tank also can handle key events and draw and update. Cool, I can look into how it does that later.__

The emphasis there showing that on this first high-level pass, you don't really need to know how the Tank works. You can guess that it uses key press events to change its turret angle (and, later, its firing power), that it draws itself and can update itself (again, whatever that means, not important now). The big thing you're getting on this first-level pass is: "there's a game Window that initializes and creates Tanks and draws and updates them." This hopefully demonstrates the principle of "encapsulation": bundle up things that a user doesn't really need to know, and give them a nice shiny set of buttons to do the things that they actually care about. The game (as a user) doesn't care to know how the Tank updates it's turret graphic; it just needs to know that it can do that. Thus, the interface exposed to the Game by the Tank is "draw" and "update" and "on_key_press/release". That's all the Game should care about.

The programmer of the Tank obviously needs to know how it works, especially when you realize that you did it wrong and need to fix a bunch of crappy logic bugs.

The List and Cycle

I also switched away from making two separate, distinct player objects as member variables of the BlackEarthGame class (I'm referring to self.player1 and self.player2), and instead went with the idea of "well, I'd really like to be able to just tell the game to make X number of players, and then I can test switching between more than just two of them." I put some (hopefully) extensive explanatory comments near this stuff to explain the reasoning behind using a itertools.cycle (which, by the way, it took me a while to realize that that was what I needed; I didn't know how to explain in words the idea, started out by searching for "python endless loop list" and it took another five or so tries to find the right thing).

Notice, too, that I did this in very small steps. First, I just took the self.player1 concept and self.player2 concept and stuck them into a list see here. Then, I practiced being able to use the spacebar to switch with that basic setup. Then I realized that I could very easily make this a configurable number of tanks for the list, and so I changed that and tested it and checked it in. Only after all that, I realized that I didn't like the way I was moving through the list and figured that there was a better way to cycle through the active tanks, and did the aforementioned Google search.

Anyways, for your consideration. I apologize if these are waxing too verbose, I'm enjoying explaining the thought process, in the hopes that it helps encourage and teach.

Closes #9 , #15