This week’s update brings two awesome new features, Leveling Up and Popups.
Since those are the two main things I worked on, I’ll just mention my other changes now. I changed the Spell UI to be a darker orange when charging so the color change is more obvious. I’ve increased all spell’s charge time, in my small attempt to balance all the new spells I’ve added.
So one of the major feature’s I planned on having in Monolith was a large leveling system, so that eventually the combat would look entirely different depending on what leveling path the player has chosen to level up.
The way I chose to implement this, is creating tons of spells that the player could unlock when they level up, if they meet the prerequisites, This way the player can get the better, higher level spells once they have unlocked the lower level spells leading up to it.
Here is a picture of the leveling menu that the player can open after they have leveled up and pressed the ‘L’ key
This is also the first time you can see the names to the spells, which I now have a new way of creating…
Before, I had a really bad way of creating a spell. I used to have each spell split up into 2 areas, combat related info, and projectile related info, which were located in two different classes… I have no idea why I did that. But now I have a whole class for creating spells, holding all the info needed to know at any time for each spell.
Since I made an easy way to create spells, I had to spend some time to actually make a few. Before this week, there were only 3 spells, Fireball, Lightning, and Waterball, now there are almost 20, some of which you can see above, the rest are unlocked after the ones above are unlocked or once you have the required rune.
Runes have had a big change this week. First of all the visual change:
As you can see, the runes are now always colored and have their own character instead of just numbers, not just when pressed, and now when they are pressed, they get a white background.
The reason for the changes? They were changed to represent which runes are unlocked and active, which now can be switched out every few levels!
Every 5 times a player level ups, they can choose a new rune to unlocked, and which rune to switch it out for.
This is also the first time the runes have names!
Runes follow the same kind of logic spells have, they all have prerequisites and the cooler ones take a bit to get to. This is how the change in gameplay really works. Because you have to sacrifice a rune to get a new one, and the player cannot replace the runes required to unlock the new one, it forces the player to give up some spells to make room for the better ones. The plan is to give options for all play-styles so everyone is happy and every leveling path is used equally, but that is the ideal scenario, so we will see how well that happens later.
There is one new UI this week, the “Level Up Ready” UI, that shows up whenever the player has an upgrade ready.
The newest addition to the UI family is the Popup UI! And I will say now, a personal favorite.
As you can see, popups fade in, stay for a bit, then fade out, and multiple popups are supported.
The way they have been implemented actually makes them really easy to add!
When a new popup is wanted, all it takes is one line of code:
And that’s all it takes to make a green popup saying “LEVELED UP TO LEVEL __” that stays for 5 seconds (1 second of fading in, 3 seconds of staying, 1 second of fading out). This particular popup appears every time the player levels up.
Right now there is a popup for:
That’s all for this week!Read More
A good bit of changes this week, but spread out enough that there isn’t that much to write about for each except for a few topics. Therefore this update will be more a list then an explanation of the bigger changes/additions.
Zoom! Pressing +/- increases the pixel scale, which is a nice feature to have.
Permanent bones. After a mob dies, the blood will dry up but the bones will stay there forever!
Decreased mob spawn chance.
Correct order of rendering. Tiles > Mobs > Entities (Particles/Projectiles) > UI
Changed colors of spell runes to be more obvious when pressed.
Large room generated as last room in level (reserved for a boss battle)
Cool down between shots and after firing. Barely noticeable between shots, but after all shots of a spell are fired, the player is unable to cast another spell for 1/3 of a second.
Pausing. If all players in a level are paused, the level is paused.
Those are the quick changes, here are the changes that deserve some explanation
More efficient rendering
I noticed, when looking at the Level’s rendering method, that the code evaluated whether or not a tile, mob, or entity, would be rendered each frame, even though there was no way that information would change more than the level updated, or even as often as the shadow map updates (which happens 4 times a second).
So I simply added a variable to tiles, mobs, and entities that enables it rendering or not, and then each frame the game would just check if that variable instead of accessing the shadow map and going through several loops. So now the rendering is much faster, I saw a 150% increase in frames per second, which is always awesome to see.
Getting one step closer to leveling up! Experience particles act the same as in most games. They are dropped by enemies on death, and move toward the player, until they are on the same tile as the player, where they are absorbed and the player gains that amount of experience.
I had planned on this week being the “Leveling” update week, but unfortunately I realized there were a few more key features I had to add before I could do that, those features I got to this week will be covered a bit later.
Player Projectiles change
Before, the player had to be locked on to a mob for their projectiles to home toward that mob. But now since mob projectiles always home, that seemed a bit unfair. So now all projectiles players fire home toward the nearest enemy!
Now for the big additions!
All rogue-like have a ton of enemies, so I had to make a way to create mobs, give them names, and give any information needed when creating the mob. So I created a class that holds a static variable for every mob that holds all the custom info for that mob. In addition to the standard info (name, health, experience dropped, occurrence rate, spells it can cast) I also added a new feature to the status bar at the top of the screen. I call these “observations” and they are just a fun little sentence that your character thinks about what they are focused on / locked onto. An example is seen below, with one of my favorite mobs I’ve created, “Long Arm”, represented with the character ‘W’,
Each mob is also given a Type, which holds a few different bits of information. The current types are: Common, Uncommon, Rare, Ultra, Mniboss, Boss.
The type controls it’s occurrence rate, color (the color gets blue depending on how rare it is), and the amount of experience it drops.
Probably the most notable change this week (even though it was added just today), is the new Menu system. Menu’s act like how you would expect, but it took some rearranging of code to make menus work.
In-game, a menu appears as any other UI, but the player cannot move while the menu is open. Right now the only in-game menu is the pause menu, which gives the player the option to resume or exit the game to the main menu, which brings me to the next point…
There is now a main menu!
Instead of the placeholder Java default dialogue box popping up asking if the player wanted to the run the server or join the server, there is now a nice menu when the game is started!
This also allowed a new option that was not as convenient before, joining external servers. There is a sub menu when selecting “Join Server” on the main menu, that lets the player decide if it wants to join a local server or an external server, which then prompts the user to enter the host’s IP address (which pops up one of those placeholder Java default dialogue boxes, but hey, that’s to be fixed another day). Unfortunately I have no idea if joining external servers actually works, as this feature was just added today and I have not been able to join external servers in the short amount of testing I did.
So that’s about it for this week, there were a few small bugs fixed that either aren’t worth mentioning or I forgot I fixed this week (not the greatest at keeping track of things this week).
I am now able to export the game to a runnable jar file, and could put the game up for download if there is anyone interested!Read More
This week I worked on one big thing that lead to a thousand problems, but it was worth it, because now the Monolith has random level generation!
So this week the first thing I got done was random level generation, which is obvious a key feature in all rogue-like games. How the level generation is actually very simple:
1. The first room is created in the center of the map.
2. A random wall is chosen, and a door is created somewhere on that wall.
3. A random width and height for the next room is generated, and then the level checks if that room can fit next to the door.
4. If it can’t fit, then the room is not created and the cycle returns back to step 2.
5. If it can, the room is created, and the cycle returns back to step 2. If the number of rooms created is equal to the maximum amount of rooms, the generation is done.
And that’s it! There are actually some really cool results that come from this, and every time the level feels different, but an average level looks something like this
Sometimes a large room full of enemies is created, or maybe the level is a series of small rooms and hallways that have enemies sprinkled in. Each situation needs a different approach from the player, and there are many ways the player can choose to deal with each room. Hide behind a door and wait for the enemy to come to you, or run and gun through each room until you reach the end as the enemies struggle to catch up to you? Both are valid solutions!
Of course, what would a rogue-like be without a bunch of enemies? When each room is generated, the amount of mobs it can fit is calculated (the mob-per-tile ratio right now is 1/75, which I believe works nicely), and then each tile in the room is checked to place a mob. Each tile has a 33% chance to create a mob (which may be too much, and I will reduce that later). When a mob is created, to avoid all the mobs spawning in the top left corner, the next tiles counted through are 5 x 5 tiles away from the mob just created.
There were some changes to mobs this week to make them more difficult to fight. Now, enemy spells also home into players the same way player bullets home into the player’s target, but now they are a bit too hard… so I will continue to find the right blend for enemies, but it may be a while before they are exactly where I want them.
Multiplayer Woes and a Thousand Small Problems
So far in this entire project, most features have been added almost flawlessly, and sometimes they accidentally create new features! But everything must come to an end, unfortunately, and the first big problem I did not plan for in advance arose. That is, multiplayer players receiving the level from the server. At first, it seemed like it was as simple as sending a packet of the level tiles, colors, and which tiles where solid or not. However, sending all of that information was too much for one packet to carry, which then created a problem, the level had to be made in parts, instead of one method creating the level as it has so far. So to solve this, the level sent the tiles and solids information, then sent the colors, and everything seemed to work. Then the multiplayer was tested…
Oh my, the errors that began with the new loading level system for multiplayer clients. Before, the code never expected the player not to have a level when the game and player is created. This through errors left and right, broke the mob AI, and in general was an absolute mess! I spent 5/7 days this week working on cleaning up that mess. The worst part of fixing it, was that sometimes the multiplayer worked fine, then the next time it is tested, the game won’t even start!
The final solution to this, was created just today, and I had to handle all situations in which the level may not exist, and completely re-write the way multiplayer works, which deserves it own section…
A New Approach on Multiplayer
So the easiest way to fix the multiplayer for all players was to treat all players as if they are multiplayer players. Before, the game that had the server running had it’s own player. Now, the server is it’s own game running with no player attached to it, which saved a good bit of code from having to check if X object had to send X packet to the server or client, which became confusing at some times. Now, each player is a multiplayer player to the server, so there is no longer a need for a fix for both the server player and client player! This may be a bit difficult to understand, because it difficult to explain.
This change does make the game slightly more annoying to test now, though, because a server must be launched before a player can join to test something.
In the future, the plan is that the server would be a separate program, and I also have to figure out a way to run the game without a server for players who want to play single player.
Right now, the server acts as if it was a spectator, as it can see the entire map, until a player joins, where it just renders what the players can see. Not sure if there will be a need or want for a spectator mode, but it wouldn’t be that difficult to add now.
That’s about it for the changes this week. Not much new, but as described before, a lot of problems were created and fixed. Monolith sure is growing up quick, hard to believe it’s already 6 weeks in and so much has been done!Read More
The focus of this past week has been combat!
Also, player’s are given a random color, which is synced across multiplayer, just a fun little feature that had no other place in this blog.
Players can now lock on to mobs. This adds a completely new feature that was not previously used, the mouse! To lock on to a specific mob, the player would just click on the mob, and a circle is drawn around it. Also there is a button to lock onto the closest mob, right now bound to the ‘e’ key.
When the player is locked onto a mob and loses sight of the mob, the player is no longer locked onto.
What does locking on do you may wonder, well it does some very useful things, which will be covered in the next two sections of new features!
At the top of the screen, there is now a status bar (when there is something to display)
When hovering your mouse over a mob or a player (including yourself) the status bar will appear with the mob/player’s name, remaining health, and the tile they are currently on.
Another very nice new feature that is necessary for the combat system is homing shots. When a player is locked onto a mob and fires a projectile, the projectile will try to correct it path to fire more towards the mob. It will not correct it’s path too much, so the player still has to shoot in the correct direction for the spell to hit it’s target.
Now a mob does not have to completely line up diagonally, horizontally, or vertically for a shot to hit. This makes the combat feel a lot better, less annoying, and has the potential to allow the gameplay to feel faster than having to carefully line up a shot every time. Plus, the correcting amount of projectiles can be easily changed so if I ever want to change the feel of the combat I can easily adjust the projectile homing!
Revenge of the Mobs
Better run, better hide, because now the mobs won’t just sit around waiting to be killed anymore. They are taking back the level, one player at a time!
Mobs can now fire projectiles! The spells they can fire are assigned when they are created and each spell it casts is randomly chosen from the spells it was given. Right now, mobs can only shoot in 8 directions. In the future, the plan is that mobs using A* pathfinding will have homing projectiles.
The Move Toward mob AI also got a bit smarter! Mobs using that AI now move to get a shot on the player rather than blindly move toward the player. If a player is outside it’s maximum range, it will try to move toward the player and try to get a shot on the player.
The way it tries to get a shot is actually simple thanks to some math! Since the mob can only fire in 8 directions, it will try to find a diagonal, horizontal, or vertical position relative to it’s target. It does this by finding the distance from the player, and if the x distance is closer to the y distance than 0, it moves toward a diagonal shot, otherwise it tries to line up a horizontal or vertical shot. The reason it compares the x and y distance is because if the x and y distances are equal, that means that it is diagonal to it’s target.
And the best part of this new AI is that it almost just as efficient as the before, but seemingly much smarter! And it barely took any additional code, in fact here is an image of the entire Move Towards mob AI pathfinding
And that wraps up the changes, which may not be a ton in terms of a big change since last week, but a lot has been added that will be very useful for the rest of the games development, such as being able to use the mouse in-game.Read More