No, it’s not an April Fool’s day joke; the prototype for ts-tennis (play here) is now completed! Well, depending on what you mean by “completed”. Allow me to explain.
The course also comes with a textbook that Chris wrote as a part of his Gamkedo training courses, which covers everything from the video course but also includes “exercises” designed to let you flex your game design and development muscles. These exercises start out simple and start to get more complex. As of today, I’ve officially finished the last such exercise, making the first game “complete”.
I use quotes around that word because there are still a ton of things that could be done to the game to polish it even further, but for my purposes here that’s outside the scope of what I’m trying to accomplish. This seems like a great lesson on how finishing a game can be the hardest thing. Not only because the last 10% takes way longer than you think, but also because it can be hard to disconnect and call a thing “done”. It would be easy to spend even longer polishing things, but is that really needed for a simple Pong clone?
I spent the last week finishing up collision detection between the ball and the paddles and ended up retooling everything yet again at the last moment. I was going for a really pixel perfect sort of thing in which the ball would never intersect with the paddle visually no matter what, but in the end this is a little more complicated than it first seems. The desire to keep poking and prodding at that is pretty high, but at the same time I’m trying to make games, not a realistically modeled pong simulation.
What I have ended up with is a compromise that I can live with. Things are set up so that the collision bounds for the top and bottom of the screen are the radius of the ball away from the edges, and any time the ball reaches that point or farther (i.e. visibly goes off screen) we push it back along the reverse of it’s currently velocity vector until the point where its edge is just touching the screen, so that it never visibly leaves the screen. This is really easy to do because we can easily say that the upper bounds is exactly y=10 all the way across the screen (for example).
This doesn’t work so good for interactions with the paddles, however, and so in that case the ball is merely constrained to the exact spot at which it intersected the paddle, which means that it is always exactly half way into the paddle visually at intersection because its position is relative to its center. This is not that big a deal since it’s moving pretty fast anyway.
I experimented with similar logic to the screen bounds, but it produces weird artifacts when the ball is coming in at a steep angle (for example) because the ball can get pushed backwards farther than it moved this update in some cases. This is because the “real” intersection should happen when its center point is exactly radius pixels away from the edges of the paddle, since that’s where it visibly intersects. Instead, the code uses the center point, which means that it could be visibly intersecting this frame, but not considered to be, and then on the next frame it is and it goes backwards to a position prior to where the frame started,.
Clearly there are ways around that, but I’m considering this a lesson in “good enough”. We are talking about a clone of Pong written in TypeScript to run in a web browser at a relatively low frame rate; I don’t think the ball visibly intersecting with the paddle is the end of the world as we know it by any means.
In the meantime, I’m enjoying my second victory of the year (the first being my completion of the Dr. Mario clone I did for Devember). It’s a great feeling, I must say!