Python Space Invaders on GitHub

We’ve managed to import some bitmaps and display them. It’s time to start sketching and executing a plan. Then I ask myself a hard question, leading to a complete change of direction!

Let’s be clear here. I do not intend to list out what we’ll do in the order we’ll do it, and the march according to that plan. I strongly believe that to do that is somewhere on the line between Impossible and Ill-Advised. Let me tell you a story.

Back when I was trying to manage software efforts, one of my finest reports was a fellow I’ll call John. John was an excellent planner. He could break down any product into any number of detailed steps that needed to be taken in order to get the thing done according to the then-understood spec. His plans were excellent. Each step made perfect sense and it all seemed to add up.

John’s particular skill, however, went beyond that. He could also associate an expected duration for each task on the list, and those estimates made sense as well. John’s plans were unassailable.

But wait, there’s more. Because he could break down any task into its components, and because, obviously, any task requires some finite smallest amount of time, no one could deny that, John had the seemingly effortless ability to show that whatever deadline we had in mind could not possibly be met. He would just break the effort down far enough, add up the elements, and Voila! there you were, needing more time than you had available.

True story, and the lesson may not be what you think. If the question was “can be be done by this date”, John could prove that we wouldn’t be done, and sure enough, we wouldn’t be done. Worse yet, some things took even longer than John had estimated.

At the time, and this was many years ago, I was at a loss, because so far, life had taught me that my teams could never get it all done by whatever deadline we were given, and John had pretty much shown us why. And I was not smart enough to work things out.

Many years later, Chet Hendrickson, looking at a similar situation said “It’s not that we don’t have enough time, it’s that we have too much to do”. He may have put it better than that, those may not be his exact words. But he had it right.

Faced with a deadline, the trick isn’t to get all the work done by the deadline, the trick is to get the best combination of things done by the deadline. In short, manage scope, not time.

Now if I were building a product for someone, what would I do differently from what John and I did back then? I’d do something like this:

  • identify the major desired features of the product;
  • identify the major technical challenges of the product;
  • eliminate critical challenges early;
  • deliver features early and often, in order of importance.

What do I mean by early and often? Well, it probably depends on whether you’re building a compiler, an operating system, or a Space Invaders program, but I would do my best to have working code to demonstrate within a week or so and every week or so thereafter. If my management had any kind of deadline in mind, I’d want to start showing them real results well before that deadline.

We’ll debate at another time what you could do on your effort, which is obviously so large and so difficult and needs all its features so badly that no small chunk of it could possibly ever be delivered. Feel free to engage me on Mastodon and we’ll talk about it. Maybe I need a Discord. God, I hope not.

But for Space Invaders, let’s see what we can figure out. Here are some random thoughts. Imagine that I’m writing them on cards. In real life, I might actually do that.

Animated Invaders
I’ve spiked importing the bitmaps, and have a source for all of them. There is no technical risk remaining, in my opinion, and a couple of days’ work to bring them in. We should plan to build a little subsystem for import, because we may be asked for new art, we may be maintaining the program or porting it, and because when we do work here, we simulate larger projects with longer ongoing changes.
Collisions
As usual in games, we’ll have to detect collisions between various bombs, missiles, invaders, shields, and players. For most purposes we can almost certainly use simple determinations of whether the objects’ containing rectangles are colliding. I foresee no particular trouble for most cases. There is an issue with Shield-Bomb damage however:
Shield Damage
The invaders drop bombs, and there are shields at the bottom of the screen that the player can hide behind. When a bomb hits a shield, it blasts away part of that shield, and it should look like the bomb really did it. The hole in the shield should be ragged, positioned where the bomb hit, and might ideally even look like the shape of the bomb. (They have interesting animated shapes.)

Technically, this will require us to modify the shield bitmaps on the fly during the game. In prior games we’ve done here, we have typically erased a colliding object, perhaps replacing it with new ones, such as split asteroids, or exploding ship fragments. Here, I think we’ll have to modify the existing bits.

I am confident that we can do that, and expect it’ll take us a few days’ work to get it looking good.

Invader Sideways Motion
There is a special aspect to the invader motion which we need to emulate. On the original machine, there wasn’t time to move all the invaders in a single frame. In fact, the game only moved one invader per frame. Since there were 5 rows of 11 invaders, one step of all the invaders takes almost a second to complete. If you watch a old video like this one you can see how the ranks kind of ripple, one invader at a time.

We will want to follow that same scheme, moving one invader on each frame. It may take us a few tries to get it looking good. We foresee no deep difficulty.

Invader Downward Motion
When the endmost invader gets close enough to the side of the screen, motion reverses, and the ranks step down a couple of pixels. We’ll have to figure out how to recognize the endmost. My current idea is to start with 55 invaders arranged left to right, top to bottom, in a list, and to remove destroyed invaders from the list. We can afford this because our computer is about a thousand times more powerful than the original. If we arrange this list properly, I think we can be sure that the left most invader is always first and the right most always last, no matter which ones get removed.

I’ll need to do a little thinking and such to be sure of that. Worst case we’d just have to scan them finding the max or min x value depending which way they’re moving.

Invader Representation
The original game seems to have had a fixed allocation for 55 invaders, and if I understand the comments on the original program correctly, positioned each invader relative to the bottom left invader (whether it was alive or not, I guess). That would mean that the code just had to compute that starting position, and then each other invader’s internal position would just be a fixed x and y away from that. That would allow the game to avoid storing each invader’s position.

What I do not understand about that is how that plays against the motion topic above. Was it the case that the game only drew each invader once per full cycle through? Because otherwise, if we move the first one and the others are in sync with it, they’d all move at once. More study would be required in order to fully understand what the old program did, but our mission is to look like it, not to copy its workings.

I think we’ll simply give each invader her own x and y coordinates and update them one invader per cycle.

Bombing
There was some pretty intricate stuff going on in the bombing, with two types of bombs just falling from a random position, and one type always being dropped directly above the player. I believe that the targeted bomb dropped straight down from where it started: it just started above the player.

We’ll have to decide how much to emulate here. I imagine that the bombs fell more frequently as the game goes on, and will have to look into that. It shouldn’t be a big deal.

Saucer
There’s a little saucer that goes across the top of the screen occasionally. I think it’s just there to be shot at, and that it doesn’t attack the player in any way. We’ll have to spec out when it appears and how often but should be easy enough.
Scoring
I don’t know how scoring works but I’m not worried about it. We can do it with a well-known object or a couple of global variables, whatever.
Two Player Mode
We might want to do this. Again, I’m not worried. It might be wise to prioritize it early but we didn’t have any trouble putting it into Asteroids very late in the development.

Reuse Asteroids????

I hadn’t thought about this until just now. I’ve been thinking in terms of programming Invaders from scratch: I’m in a clean PyCharm project right now. But … what if we were the Asteroids company and they were asking us, now that Asteroids is out there, to implement Space Invaders. Would it make sense to use the “engine” from Asteroids for Invaders?

Now of course almost any team anywhere would want to start over, because that’s the fun part. But we owe it to … I don’t know who … we must owe it to someone to at least give serious consideration to using the supposedly Very General Decentralized Asteroids Engine for this game.

Maybe we should even do it twice, once with the Asteroids engine and once from scratch.

Could it work?

Let’s think about how it might work in the Decentralized system.

The basic scheme is that every object is independent of the others, all just in a “mix”. In each frame, each object gets to update, to interact, to draw, and so on. Every pair of objects interacts. In Asteroids that sort of makes sense, because all the main objects are mutually destructive. In Space Invaders, the invaders never interact with each other, never interact with the saucer, never interact with the player, only interact with the player’s missiles. With 60ish objects on the screen, naively we would have 3600 interactions per cycle, of which a maximum of maybe 5 would be interesting.

We could get around that by treating the invaders as a single object, which might be desirable anyway because of the ripple effect. That object would have a moderately complicated move, draw, and collision behavior but the interactions would be reduced from about 3600 to perhaps 100.

If we go with the Asteroids engine, we have capabilities like Score / ScoreKeeper that we can reuse, and perhaps ShipMaker / ShipProvider as a starting point for providing the player objects. We’d have the basic coin logic, the main loop, all that stuff.

Hell and damnation. It’s hard to make a case against this idea. I think I have to try it just to see what happens. My intuition is that it might work nicely.

Issues

Separate or Integrated?
Should we grab a copy of Asteroids and rip out the innards, or should we build Space Invaders right in the same program, with the difference being the kind of coin you insert?

I can’t make a decent case even for grabbing a copy.

Screen Shape
Invaders had a not quite square playing field but it is close enough to shape that we can probably just let it be.
Controls
I was planning to use the keyboard anyway, and we know how to do that.
No Danger
I don’t see any major obstacles to using the Asteroids engine. So far, I don’t even see anything suggesting it’ll have to change. We’ll see about that as we go forward.

Conclusion

Fascinating. I was really thinking that I’d do a clean sheet of paper Space Invaders, just for fun. And, I still might. But I think I owe it to myself and to the universe to try doing Invaders as a second game inside the Asteroids shell.

The requirements and much of the thinking above is probably still good, at least close enough for now. We’ll have to deal with the details, and some of them may be differently difficult or differently easy, but the behavior has to look the same.

Wow

I am honestly gobsmacked. I really wasn’t thinking of doing it this way. But we have to, don’t we? We simply have to find out how well—or poorly—this works. Maybe after that, I’ll do it again from scratch.

Next time, back in the Asteroids repo!