- Team Members
- Summary
- Instructions
- Design and Implementation
- Architecture
- Code Design
- Implementation
- Testing
- Extensibility
- Known Problems
- Comments
- Sid Shekhar - https://github.com/sidshekhar/
- Philip Kinhasa - https://github.com/downtocode
SteamMaku is a 2-dimensional competitive bullet hell game. Two players move around the playing field attempting to hit each other and other moving targets with projectiles. A player can win by shooting the other player a specified number of times, or failing that, by accumulating the highest score when time runs out. All coordinates in this game are indexed as (x; y), where (0; 0) is the top-left corner, the x-coordinate increases to the right, and the y coordinate increases downward. The playing field has size cBOARD WIDTH by cBOARD HEIGHT. The game lasts cTIME LIMIT seconds, and one timestep elapses every cUPDATE TIME seconds. These two are the only time quantities that are given in seconds; the rest are all given in timesteps. There are three types of objects in this game: player characters, bullets, and UFOs (unidentified flying2 objects). Each of these objects will be described in more detail within their own section, but they all they all share some attributes. The first is an ID, which is just a unique number assigned to every object in the game, for purposes of communication with the GUI. The second is a position, which is where that object is on the playing field. The third is hit radius, which is how large that object is; specifically, this is what is used to determine whether two objects are in collision.
To compile our game we just use the make Game command. Then we run the java so we can do make GUI. Then, after we press connect on the GUI, we run the two bots with the localhost and port number as arguments. We do this having four terminals open in the correct directory and typing in the following commands in each respectively:
./game.exe
java -jar
gui_client.jar
./botname.exe
localhost 10500
./botname.exe
localhost 10500
Modules: We used most of the modules that were given to us such as Game, Util, Connection, Definitions, and Constants – from which we used different functions. The only provided module where we actually implemented the game was in Game where we updates handle_action and handle_time to deal with advancing the state of the game for every timestep in handle_time and changing the state of the game to reflect actions taken in handle_action. To store all the helper functions of handle_action and handle_time and to keep track of game data and team data, we created another module called State. Most importantly, we defined the type game in the Game module to equal the type game from the State module, which held mutable types for game data (game_d), directions, whether or not the players were invincible, and how much time had passed.
The State and Util interface allow Game to use functions that could aid in the implementation of the different updates and actions performed in the game. The base types for all the different types of objects used in the game such as bullets, player characters, team data are contained in the Definitions module. Additionally all the constants used throughout the game are held in the Constants module. The information from these two modules are accessible and are used by other modules in defining specific functions for the creation and movement of these objects.
We used while loops to loop through the creation of different bullets with different velocities and angles and created records for each bullet created. We used records with mutable fields for the count – when keeping track of each bullet created – so that we could change some aspect of a bullet with every successive creation.
We used a top-down approach to implement our game – breaking it into its separate components before commencing the programming of separate functions and modules. The first challenge we ran into while coding was deciding how to store what state our game was in at any stage in the game. This led to our creation of a state module that kept track of state, team and game data, and also was a convenient place to store helpers to keep away from cluttering the Game module. We also encountered the challenge of thinking about how to store bullets in a structure where they could be accessed by id (such as a hashtable) but at the same time deliver an end result of a list of bullets to game data. Roughly we divided the labor by having one of us do handle_time and another do handle_action. A such each of us added different functions that would be useful to us in State and at the same time utilized what we needed from Constants, Definitions and Util.
After every block of code either of us wrote that performed an action, we first checked if it compiled with the larger program and then of it was something that was to derive a result, we tested only that block separately on the command prompt and used print statements throughout the block to make sure that it works. In terms of the GUI, we tested not only whether the graphical updates were sent appropriately by seeing if they appeared in the GUI but we also kept in mind how the internal state of the game should be changing and so kept track of what an object once it appears on the GUI must do – in order to fulfill the properties of the game given to us.
One can easily add additional features to our code. One can add a new module in the Game, Shared, or Team folders depending on which part of the game one wants to change. If one wanted to add new bullet types, or new collectible items (besides) for example, one could add their type definition in the Definitions module and then could write functions to implement those types in either the Util module or the State module. Then these implementations could be initialized in handle_action and handle_time. More interesting bomb effects could be added by creating a new function in the state module describing what effect the bomb will have on the game data arguments. To create neutral enemies that fire at both players, one could edit the team_data and game_data types to add an element “enemy” to the tuples. Then a type “enemy” can be defined in the same module detailing different elements that one wants the neutral enemy to have. This new type of enemy can then be updated through the State and Game modules as part of updating the central game data (changing the state of the game and the elements in it).
We know that our GUI sometimes lags when too many bullets are fired in succession and at certain stages of the game. There are also white clouds that form in the middle when clearing bullets – thus obstructing the view for us. Essentially, the GUI and the Game state are slightly different in that what we do to update the GUI does not fully reflect the changed game state underneath (where it works correctly).
We felt that this project was overall a fun experience to carry out because of the game-aspect and because we could see the results of our work in the GUI. We spent a good amount of time on the assignment about 3 days straight coding. We would have liked to see a working version of the GUI so that we could know what to work towards – this would have especially helped when we were testing.