Skip to content

Latest commit

 

History

History
24 lines (14 loc) · 7.18 KB

README.md

File metadata and controls

24 lines (14 loc) · 7.18 KB

PLEASE READ THIS SECTION

The control for Wanshot is rather controversial. Many folks prefer the common WASD movement, but I feel that the movement I have installed for Wanshot gives the game more depth and uniqueness, as it is closer to what controlling a tank actually feels like. Like the typical WASD controls, W moves forward and S moves backwards, but the A and D keys are where it differs. Pressing D will rotate the tank clockwise and pressing A will rotate the tank counterclockwise. The body of the tank will determine where the front and back of the tank is, so when pressing W and S they will follow the angle that the tank has been rotated to. I have added exhaust particles at the back end of the tank to help differentiate where the front and back of the tank is.

If you wish to compile this program yourself, you MUST specify to your IDE that the Java resources folder is the one in the repository marked as “resources.” This process differs between every IDE, so use best judgment while doing so. I know that compilation can be hectic and the process may be a little different between every device, so I have also attached an executable JAR file in this submission as well, in the case that this isn’t compilable–that is, if this is being read from my APCS final project submission. Otherwise, if this is being read from my github repository, tinker around and I’m sure you’ll figure something out. Please note that, since I have compiled my project in my Eclipse IDE, using an older version of Java, this runnable JAR file will NOT RUN in Java versions 1.8+. You MUST use Java versions 1.7 and below to run.

Demo: https://www.youtube.com/watch?v=45YhlCFXV-E

This project is inspired by the Wii Play minigame, Wii Tanks. I’ve always enjoyed video games with a simple style, so my favorite games are mostly web games that do not use any complex rendering system. Wii Tanks has always been my favorite childhood game due to its simple yet vibrant style. When I picked up on programming, I wanted to make a fangame for it as soon as possible, and that is exactly what I did.

Wanshot is not actually the first fangame I made for Wii Tanks. I’ve made another fangame for it in the same style as Wanshot; however, it is much more complex, allowing for a level editor system with multiple set levels. I made that one in JavaScript and it was my summer project. I was satisfied with the results, but I didn’t do well programming how the bots function. After doing more research into how it should be done–and especially how the original game went about it–I felt ready to refactor my game. It, however, was too far along and I didn’t have the time and energy to dig through hundreds of lines to make the necessary improvements. Thus, I took this chance with my APCS final project to finally get my programming “plot bunnies” out.

Wanshot is completely made with java swing. No other rendering systems that were not taught in class were used. Instead of using the standard Graphics paint component output for rendering, I typecasted it to Graphics2D in order to rotate. I also turned on anti-aliasing in swing in order to ensure that the graphics do not turn pixelated.

I decided to go with a model view controller design. I hooked up a global update and render function to both the model and view classes in order to ensure that the game updates at a reasonable pace while being as smooth as the computer running the game can achieve. I kept track of the delta time with System.currentTimeMillis(). Within my overall game loop, maintained through an infinitely running while loop, I first update the current elapsed time since the last update by calculating the difference between the current time in milliseconds and the last updated time in milliseconds. Since I want my game to update at 60 frames per second, I convert my elapsed time in milliseconds to seconds by dividing it by 1000. If the elapsed time in seconds exceeds 1/60th of a second, I quickly call a succession of updates until I make up for my exceeding time. This makes sure that I get my updates in the unstable environment of every computer–stuttering may occur. After the update sequence ends, I update the variable keeping track of the last update to the current system time.

For audio playing, I keep all my sound effects in a resources folder, listed on my Eclipse IDE. By using getClass().getResource(url) I can directly find the wav file, and this allows for my game to be run without any problems in an executable JAR file. I also call each one of my audio files within a separate thread to allow for overlapping sound effects.

The hardest part about this project was programming the enemy tank “AI.” The shell shooting system runs on recursive raycasting. If it detects that the shell will hit an enemy tank, it will return false–don’t shoot, and if it detects that the shell will hit the player, it will return true–shoot. If it detects that it will hit a wall, it checks to see if the shell has any more bounces left. If there are any more, it will return a call to itself with arguments consisting of new coordinates, angles, and one less bounce. If there is no more, it will return false. The tank movement system is very complex. It required a ton of fine tuning to achieve, relying mainly on trigonometry calculations with vectors. Every tank has different settings, so they have different behaviors, but they all fundamentally run on this same base behavioral program.

The core of this entire game relies on SAT Collisions, which stands for Separating Axis Theorem. Since my game has rotation and attempts to simulate an actual fighting environment, it calls for a more complex collision system. The SAT Collision system allows for collision detection between rotated polygons, and most importantly, it allows for collision resolution–running into a solid wall or pushing an object. The idea of the collision detection can be visualized as placing two polygons of any rotation into a dark room and then shining a beam of light onto them for the sides of both polygons and then checking to see if the shadows produced by the two shapes overlap with each other. If any gap is found between the two shadows, it is immediately known that the two shapes are not colliding and the process for checking whether this is the case can terminate on spot. We do a projection by taking one vector formed by taking a side of one of the two shapes and translating it to be perpendicular and then performing a dot product with it with every one of the vertices and then returning the smallest and largest dot product values. With the max and min dot products of both polygon A and polygon B, we can perform an if statement to detect for overlapping.

We resolve this collision by first getting the smallest amount of intersection with the dot products along with the perpendicular vector that goes along with it. Then, we get the amount of times our vector can fit in the amount of this intersection, and then we normalize our vector to purely get the direction of it. When collision is detected, we can then “push” out the object we want by adding its coordinates with the direction of the normalized vector multiplied by the number of times it should be pushed out.