So after passing the CCNA exam recently, I have come to recognize it as a sort of crossroads in my tech journey. For nearly four years I've been casually studying computer programming, spending a considerable sum on programming related books, and living in a relatively negative mental state as a result of beating myself up constantly for not having become a software engineer. As I've written previously (and rather repetitively), much of the hold-up has been my own inconsistency in focus, although I have to admit a considerable challenge has been a tech related social media addiction that has consistently left me feeling inadequate by comparison to others in the field, causing me to rip up any project I begin in search of something more "worthy" of HackerNews. My previous post about breaking the chains of social media addiction actually did eventually yield some results. I've been off HackerNews for at least a couple of months now and have recently (about two weeks ago) began denying the urge to check news headlines. I wiped my YouTube search and watch history and have been consistently avoiding tech related videos.
The fruits of these exercises were somewhat slow to arise (if you call a couple of months slow compared to years of habit) and quite subtle, yet amazingly powerful. For one, I have actually been able to maintain a focus on a project idea without coming to find it stupid after looking at what others are doing. I've come to accept that I have a certain line of interests, and that's a good thing. I like classic video games. I like old computers. I want to create 2D "pixel" styled games from scratch although there are frameworks and libraries and engines that I could use. I want to write emulators of old computer hardware from scratch even though others already have done so. I want to learn the internals of the web that are "unnecessary" to learn because there are frameworks that take care of those functions. Now, it may seem like the same old spiel, that every geek out there feels the same way. The thing is that I'm starting not to care what others are doing or what they feel. I like these things because the interest me. This opens the door to something powerful: I'm beginning to separate the career stuff from the personal interests. This means that I can finally begin to utilize the knowledge I've gained.
I need to engineer some way of storing the "pixels" in such a manner that I may write an algorithm for quickly accessing any pixel likely via offset from some set point much as with memory addressing in Assembly language programming (gush!). Naïvely, I imagine a single dimensional array of pixels (if the gameboard is 80x80 there will be 640 pixels) and some math that will divide them into rows. For instance, given a screen of 80x80 the first row will consist of pixels 0 to 79. If I need to know which row a pixel is in, I could take the index of the pixel and divide it by 80, if it yields a number less than 1, I know it's in the first row, if it's greater than 1 but less than 2, it's in the second row and so on. The question becomes whether this constant computation will be efficient enough to allow rapid re-drawing, which brings about the mention of the offset. Since the position of my "pixels" will relate to the actual display's pixels, I'll have to use the bounds of each square (defined in actual display pixels) to set the location of the next pixel. The math to do this could lead to the "addressing" method in that a square's location (it's top left corner in Java) could act as its "address", allowing me to re-draw via a simple loop that draws a square (a "pixel") at each location ("address") with the specified properties such as color as dictated by the game's state. I'll have to define the timing of the game loop and when and how the drawing/updating occurs. Right now I imagine, re-drawing each row sequentially from top to bottom at least 30 times per second. This likely is a fairly inefficient way of redrawing the screen, however my goal for this initial iteration of the project is to be as procedural as possible. I want to use as little OOP as possible, there will be enough already as I'm using the Java Abstract Window Toolkit (AWT) and I'll have to comply with its inheritance structure. The squares or "pixels" will likely have some relationship to the Graphics2D class, with custom fields and properties added for utility. Choosing to use AWT rather than Swing or JavaFX is a part of a larger goal of working my way into understanding GUI development in Java from the beginning. I don't want to get into things like double-buffering right up front, I'd like to naturally get to see why those techniques are necessary and how they work.
The rest of this post will read like a live journal. There will be revisions and a lot of thinking out loud. I will post the code on my GitHub page.
This isn't really what I'd call progress but it's an important step. I'm using the book Java: Complete Reference, Ninth Edition by Herbert Schildt as one of my references. Using it I've got a built a basic frame with a keyListener that calls the Frame's paint() method, drawing filled rectangles sequentially continuing on the next line after reaching a certain x position. As I said, this isn't really progress, as the code to do this isn't at all useful in itself. However, it has allowed me to become familiar with the fundamental elements that will compose the gameboard, namely, the fillRect(), paint(), and repaint() methods. I'm now proceeding to begin to engineer the game loop. One technique I intend to use in building this project is to build little mini-projects as I go along that accomplish some sub-task necessary to the whole. Right now, the sub-task is to understand timing and build a drawing loop that draws the gameboard one "pixel" at a time from top to bottom at a rate of five pixels per second. This may sound painfully slow, but the goal for this mini-project is to precisely understand the mechanism of the game loop, I can speed it up to the proper frame rate later. Upon completing this sub-task, I will have understood how to update the screen, how to control and define the timing of re-draws, exactly when any necessary updating tasks need to occur, and how to clear the screen of the old contents before beginning the next iteration. There are likely aspects of a game loop I'm unaware of right now, or some that I don't grasp quite correctly, but my hope is that this mini-project will help clear those things up.
I've made some headway into understanding the game loop. I've referred to several books, Programming 2D Games by Chris Kelly, Fundamental 2D Game Programming with Java by Timothy M. Wright, and to a degree Game Coding Complete, Fourth Edition by Mike McShaffry. I have always struggled to comprehend the sequence of events that lead to the game screen being drawn and redrawn. A part of this confusion comes in large part from the nature of my platform of choice. To draw on a Component you must override its paint() method. You may then update the game state and have those changes drawn via a call to repaint(). However, there are subtle differences in how these methods work that may effect drawing performance. For one, calling paint() or repaint() leaves the decision of when the drawing actually happens up to Java so just because you call the method from your code doesn't actually mean the drawing will happen precisely then. According to the Wright book this is called passive rendering, as opposed to active rendering where you control precisely when drawing occurs. Active rendering though, brings in more complexity than I am prepared to comprehend for this simple project. Secondly, the Wright book uses the Swing library while I intend to use the older AWT. Wright's method of calculating the frame rate and his sequencing of the paint() method were very helpful however. The Kelly book uses C++ and Microsoft DirectX. Kelly's description of the components of timing finally brought some clarity to the logic behind calculating the frame rendering time. An additional reference, Game Programming Patterns by Robert Nystrom has proven the most helpful so far in that he begins his explanation of a game loop with an over-simplified, inefficient game loop, improving it incrementally explaining why as he proceeds. This has given me a general idea of the sequence of events that lead to proper on-screen animation. I will begin sketching out my own game loop from here.
Initial Post 01/05/2019 03:18:00PM