Tetris.mp4
Major C++ Project. The following is a write-up handed in with the assignment.
If I was developing my major c+ project outside of class the main target audience for the program would be anyone who enjoys playing classic games; however, because I am writing this program for marks, I need to take that into consideration. The first priority for the program is to make sure that I can try and achieve full marks on the rubric and then I can take the user audience into account afterwards. Much of how my code is structured and designed will be based around the rubric. The audience of my game would most likely not have a knowledge of programming nor should I assume that. My game needs to be very user friendly and include simple directions on how to play and what controls are given to user at any time. My game should not be frustrating to get working but rather should be playable from the instant it starts up. I am going to use the same keyboard controls that are defined in the official Tetris guidelines so hopefully my clone of the game will be very easy to pick up for anyone familiar to the original Tetris. In the same vein, my game should hopefully be as close to the original Tetris as possible because that is what people would expect from a Tetris clone.
Defining the end goal for my major C++ project is a little bit easier than it would be if I had come up with a brand-new original idea. Because the entire point of my program is to mimic the official Tetris game the goal is to get my program as functionally identical to the original game as possible. There are many things that are required to be added for this program to succeed but the basics are having a way for the user to interact with the program using their keyboard and then using the inputs to move, rotate, and drop the pieces. I need to include all the game physics that Tetris uses such as moving the piece slowly down the screen at set intervals, detecting when the current piece hits another piece or a wall, and clearing/breaking lines when they are full. When shown my game the audience should immediately be able to recognize what the game is and if they have played Tetris before, how to play it. There are still many other features that I want to make sure make it into the final version of my program but meeting these basic requirements means that I have succeeded in my end goal.
As mentioned above there are still many features that I consider necessary to be added to my program for it to meet my expectations. One of these features would be making sure that I have some resemblance of a proper start and end screens. During the game the user needs to be able to see their score as well as what level they are one and preferably how many lines they have cleared as well. All of these additions are visual and I need to make sure that they look good and fit in well with the theme of the program. I want the code of my program to be written in an object-oriented way that makes use of classes for both the entire game itself as well as having all the pieces being part of one Figure class. Getting input and output is very easy using the SDL2 library as all I need are a few switch statements to check if certain keys are pressed and then I can do things based off of those actions. The way that I am going to keep track of all the pieces in the grid is using one massive 3D array that holds 22 rows of 10 columns and then has each square hold an array of RGB values. This will make it easy to move the piece down by one each interval because all I have to do is move it down one row in the array, the same goes for moving the pieces left and right. Checking piece collision also works very well with an array because I just have to check if the surrounding squares contain the values (0, 0, 0) meaning that the square holds that black color and is empty. The biggest concept I will need to learn to get my program properly working is how to use the SDL2 library. SDL2 is built upon OpenGL and allows for the creating of 2d windows and the ability to draw shapes on those windows, I have made very few programs that make use of 2d graphics so I am almost starting from scratch but I am confident that I will be able to learn the library and use it to make a good program.
Throughout the prototyping process much of how my game needs to be made came from playing the real Tetris game on the official tetris website as well as looking through the wiki pages made for the game, specifically the Tetris Guideline Wiki which contains all the official rules for the game as well as some harder to find background rules such as how much time it takes for the pieces to fall at each level. I commonly use the website GitHub to store many of my personal coding projects from home so I decided to do the same with my C++ project because it was the easiest way to keep track of every iteration I went through with the program and it also allowed me to attach a comment to every commit. GitHub was also the easiest way to transfer my program back and forth between school and home.
During multiple stages of creating my program and after I made large changes that would affect the user's experience, I gathered feedback on how I could improve my program by adding, removing, or changing certain things. One piece of feedback that I got towards the end of my program was on how the user would know how to play if they had never played the Tetris before. At the time my game had nothing on how to play so I later added a help screen that can be accessed from the start menu by pressing 'h'. This menu shows each of possible keys that the user can press while using the program and a few words describing what the key does. On the other side of the screen there is a description on the game Tetris and what the objective is. Underneath that there is also a small table showing what actions score points and how many points are given for each action. After completing this menu, I think it added a lot to the program and would be a big help in getting people new to Tetris started.
Throughout the development of my program, I kept track of all my iterations on my GitHub and all of the commit information is available in my public repository at https://github.com/DevenMarrero/Tetris, this link leads to the current version but if you click the "Commits" button under the green download button you can see the entire history of updates that were as often as twice a day because I would save to come home and go back to school.
Getting the program environment setup in the beginning took a lot of debugging and research as I needed to figure out how to add the SDL2 library to both XCode at school and Visual Studio at home. Both used completely different processes to link libraries and the Visual Studio way was more complex however there was more information on how to do it and after following the short video on YouTube it was working. Setting up the library on XCode was much harder because I could not find an easy tutorial on how to do it and was left own my own to figure it out. Eventually I found that if I move the library to the same folder as the XCode project and then press the link framework button it would work. The only small issue that I could never find was every time I wanted to build my code I had to delete the old build folder using the clean command and then it was fine.
Going through the commit history commit 10 was the first time I had setup SDL2 and got a working black screen to show up, Later the same day in commit 11 I had gotten a figure to fully render on the screen and at this point I had learned most of what I needed to know for SDL2. The first major checkpoint I had reached was at commit 15 where the figure could fully move left, move right, and rotate using the player input. A day later in commit 17 my program started to feel like a real game as I had given the pieces the ability to fall and stack on top of each other, they had yet to break apart when the line was full but that was added later in commit 18. The rest of the changes to the program were mostly visual such as rendering text and scores as well as adding the start and finish screen, the last piece of gameplay came in commit 23 where the hold piece and next screens were added but not rendered. The mark of my completed game came with commit 32 which suitably named "STABLE BUILD" because at his point I had a program that met my basic goals and if anything that I tried to add afterwards failed I knew I could return to this commit and have the game still be in a fully working state. The only things added afterwards were visual changes to the start and finish screen as well as creating a help screen that explains the controls and the goal of the game.
Right before I made the stable build commit, I had run into a large issue that would cause my program to crash and give an EXC_BAD_ACCESS_ERROR but only when the program was going to close. At first, I ignored the crash because to the end user the program closed normally but later I decided that I wanted to find the issue. Finding a bad access error is extremely difficult because it means you are trying to access a value in memory that either doesn't exist anymore or never did in the first place. The error is then thrown when you try and access this nonexistent memory and this makes it hard to find because you don't actually know when the memory was erased or what it was. I tried debugging this using Zombies which is a tool built into XCode that places zombie objects into memory that your program erased. Then when you try and access the erased memory the zombie can teel you what it used to be and when it was put there. Unfortunately, I had one of the cases where my problem was not memory being erased but not existing in the first place so the zombies didn't work and I was on my own. I first reverted back to the commit that I had made before the error started showing up and then my plan was to slowly start adding back the new pieces of code until I hit the error. After adding a few things in with no problems I reached the part where I expanded the playing grid from 20 lines, the amount shown to the user, to 22 lines so that I could spawn the figure above the grid and have it fall onto the screen. Everything seemed to be fine as I had changed all of my for loops to go through the higher range but I happened to stumble across the line of ode where I initialized the playing field. It was here that I forgot to initialize a bigger grid and because C++ is not an interpreted runtime language like python it let me access and use the grid in memory that I didn't initialize but when I closed the program and it tried to clear the memory it wasn't allowed to was when it threw the error.
After sharing my completed program with family members as well as a few friends that could get it working all of the feedback that I got was very positive. Most comments were about how similar the gameplay felt to the real game which was my end goal for the program so I feel that I have succeeded in achieving that. I had a ton of fun making this program and in the process I learned a lot about C++ and making gui's using SDL2. This project has become the second largest project I have worked on and completed and I am extremely proud of what I was able to create. The design of my program is part of its success because the entire game is a class that is then implemented in the main function. If I had a bit more time and knowledge about C++ classes and pointers I would have implemented the classes as header files as is considered the proper C++ way to do it. Part of the program that I did not include into the class and instead added outside of it in the main function was the piece of code that limits the framerate of the game to prevent it from being run as fast as the computer can. I would rather have just created a tick method built into the class that would have made it easier to implement the Tetris class into another file. The most challenging parts of creating the program in terms of finding a solution to the problem was coming up with how I wanted to manage the locations of all the pieces and then how I would use those locations to detect when pieces collide. My original idea for the grid was to store all pieces in one array but store the playing piece in a separate array and copy it over. This was unnecessarily complicated and slow and I came up with a better way of just storing the x and y coordinates of the playing piece. The challenge of checking for collisions was a real brain twister and was probably the single feature that took me the longest to implement. All of the pieces and their rotations are stored in a one-dimensional 4x4 array numbered from 0-15 and when they are rendered, they are converted to two dimensional. Checking collisions was very similar as what I ended up doing was taking a 4x4 snapshot of the grid around the piece and then converting those two-dimensional coordinates into one dimensional numbers. The two lines of code that took me the longest was finding what math formulas I needed to create a row and column into a single digit and back again.