Monster Hunter: Quest

Have you ever wanted to play Monster Hunter as a Turn-Based RPG that is close to how the main games work? Monster Hunter: Quest is the first game that I have coded, and it is heavily inspired by Monster Hunter Tri and Monster Hunter: World. I created everything in it besides the music and the Monster Hunter concepts. If you want more info on those behind Monster Hunter, there will be credits at the bottom of this page. The code files and a .jar file will be included at the bottom as well.

This program is entirely experienced through a GUI made with JavaFX. I had the main class, MonsterHunter, implement Application to do this. Lots of stuff must be initialized before we get to the body of the start method so that certain items can be affected by methods outside of the start method. The next section details how I approached the task of needing many varied items, but avoided writing excessive lines of code.

Avoiding Redundancy and Modularization

Some important methods for reducing redundant code would be three methods for formatting 3 different button types and a method for making a “background” image stretch to fit the current size of the window. The button methods make it easy to make changes to all buttons of a certain type, such as changing the font. All four of these methods have greatly reduced the number of lines required to get the same results since they needed to affect quite a lot of elements. In general, if you have to continuously take the same or very similar actions multiple times or for multiple objects, you probably want to think of a method you could call instead.

On the same topic of reducing how many lines of code are needed would be modularization. If you have a vague superclass that needs to be made into some very specific items, I have found it great to have a subclass pass the particulars of its item back to the superclass through the constructor of the superclass.

As an example, if potions have very particular stats compared to other items, they can be made into a class with no constructors. All of the stats of this item are placed into the spaces of the superclass, “InventoryItem”. Even methods can be passed this way through a consumer object.

The superclass will need some general methods to allow this, but it is much easier that rewriting a bunch of similar methods using the specifics of the item. Methods can even be written in the superclass to check over lists in the subclass for purposes of, say, crafting. With this sort of set-up, only a few key pieces of information are needed to make the base item of a potion, then all it will take is a simple new Potion() and you’ve created a potion object. This also helps with the concept of hiding the inner workings of the code. Someone else that wants to use this object just needs to make it instead of trying to figure out the specs to use in the constructor.

A great friend of modularization is combining methods into objects. As an example, a “Great Jagras” is a Giant Monster. It has some basic stats like its name and hp, but it also needs an attack for each of the 4 directions. It might seem like individual methods might be needed, especially to keep customization options open, but each attack can actually be made into an object. All that needs to be done is identify everything that makes up an attack. In the case of a monster’s attack, there is the base damage, but attacks usually have a larger area of effect than where they are intended to hit. This means that not only is a hit chance needed for the main part of the attack, but it is also needed for possible graze hits as well. On top of that, monsters can inflict status effects with certain parts of their body. This might seem like a lot to type out, but making each attack as part of a method would result in many more lines of code and, subsequently, more man hours of typing everything up.

Building a Heads-Up Display

A big part of making a game is giving the player the info they need in an easily accessible manner. In Monster Hunter: Quest, things like health, stamina, weapon sharpness, status effects, what area they are in, and recent actions need to be visible. I used multiple HBoxes and VBoxes to group things together for easier formatting. The “scrolling” text box needed a VBox to combine three Text objects so that when they passed old messages to the next Text object, it appeared to “move” the messages up. I had a method outside of the start method which changed numbers on various buttons to match what the player had in their inventory and changed the color of the health text to match one of the status effects that the player is suffering from each turn.

Building a Re-sizable Screen

The entire application runs on only one scene. I found out early on that having multiple scenes meant that the window will resize itself to the new scene instead of keeping the size of that last scene. I got around this by just setting the root of the only scene to whatever pane I needed at that time. Even the pane for the main part of the game is the same pane used for every area. I used a method outside of the start method to adjust all elements on the main pane to match whatever area the player was in. The scene will always be adjusted by buttons unless a victory or defeat condition is met.

In order to preserve the functionality of the application with a resizing window, I had to learn about the “bind” method. The placements of objects simply relied on the other objects “pushing” them into place (courtesy of the HBoxes and VBoxes). This meant that things needed to be the right size so they didn’t push things off screen. I ended up binding several sizes to either the current width or the current height of the window. In all cases, I needed to add in some division to allow the right ratios. I needed to make sure that there was a minimum size that the window could be so that people could still tell what was going on. Some objects have a minimum size that will cause them to push out other objects if the window is made any smaller.

Handling Weapons

Weapons follow the same modularization concept as monsters, but I needed a way to upgrade them as players defeated monsters. I decided to use a linked tree for this. The current weapon is a Linked Tree Node that knows what monster it needs for an upgrade and what the next possible nodes are. This means that the object does not need to store as much information as if it knew the entire tree at once. I handled determining if a weapon could be upgraded in a method outside of the start method.

Making Monsters Move

I decided early on that the game needed the monsters to move. I had to look up how to use Breadth First Search so that I could have monsters move to randomized locations without them just randomly stepping into nearby zones. I turned each zone into a graph with lines between certain nodes. Monsters would always take the shortest path towards their randomized destination. This was also used to tell the player what options they had when they wanted to move from zone to zone. To help add some flavor to the game, I gave each monster a slightly randomized cooldown on when they would attempt to move to another part of the map. I realized that it might be difficult to track the quest monster when it keeps running around, so I decided to have only the quest monster roar when it reached its destination. I manually made the map into a 2D array so that a method could capture every direction that each zone was compared to other zones. This allows the method for roaring to just use predetermined values instead of recalculating relative direction with every roar.

Credits:

Music (Composer): Tadayoshi Makino

Monster Hunter Publisher: Capcom

Monster Hunter Creator: Kaname Fujioka

Artwork and Code: Shirley Krogel

Files:

Antidote.txt

AntidoteFlower.txt

AntidoteFlowerInventory.txt

Aptonoth.txt

Attack.txt

Bandage.txt

BreadthFirstSearch.txt

CookedMeat.txt

Directions.txt

DualBlades.txt

DualBladesTree.txt

Gatherable.txt

GiantMonster.txt

GreatJagras.txt

Hunter.txt

Ingredient.txt

InventoryItem.txt

Inventory.txt

Monster.txt

LinkedWeaponTreeNode.txt

MonsterHunter.txt

Pathing.txt

SmallMonster.txt

TigerIsland.txt

Weapon.txt

WeaponTree.txt

Zone.txt

Status.txt is unavailable, so here is a description. It contained a chance of occurring, a color, and a consumer object that would make the appropriate Boolean true. The consumer object would do something like make isMuddy true.

If you want to play the whole game or view all the files, you can visit: https://github.com/Fenrious/MonsterHunterQuest