For Vox Machinae, the team decided it was time to make a new co-operative game mode. That mode would be "Bot Stomp." In this mode up to four players face off against waves of AI enemies that would increase in difficulty the longer you play.
Winning the mode is determined by a self imposed limit of number of rounds completed, or a high score of number of waves completed, within a time limit.
Ending/Losing the match of Bot Stomp occurs when the win condition is met, or no players remain on the battlefield.
As the gameplay programmer the first problem I had to tackle was how on earth I was going to spawn in waves of enemies with increasing difficulty. With that in mind, there are three main parameters that need to be accounted for.
The number of players should increase the difficulty to compensate for the extra fire power.
The host should be able to pick a difficulty setting.
The difficulty must increase each round.
In order to factor in the above, I decided it would be nice if the parameters could all be aggregated together into a single number. So I did just that, which simplified the problem to this.
Given a difficulty value, create a distribution of enemy combatants such that it is varied and greater in perceived challenge than any preceding difficulty value.
This matches very closely with a dynamic programming problem known as the knapsack problem. The knapsack problem solves the following.
Given a set of items, each with a weight and a value, determine which items to include in the collection so that the total weight is less than or equal to a given limit and the total value is as large as possible.
For more reading on this algorithm, and an example implementation, see this wonderful article. https://medium.com/@fabianterh/how-to-solve-the-knapsack-problem-with-dynamic-programming-eb88c706d3cf
Using this algorithm, we can pick the distribution that gives us the highest challenge. Each item will be a type of grinder, its value will represent the perceived difficulty (higher being more valuable), and the weight will influence how many we can fit given a difficulty number. But we need to be careful.
If we think about the mechs/grinders in Vox, we can rank order them by challenge. We'll assign a value based on the challenge the player would perceive for a given grinder. For example the heavy Dredge will get something like 8, and the light Driller will get a 3. Then we will assign weights.
This is where the magic happens. It would be pretty lame if at higher difficulties we only got Dredges appearing. So for every repetition of a grinder in our collection of "items", we will assign an increasing weight. That way, when we run the algorithm, it will pick less difficult enemies as it tries to optimize for the greatest value for the given difficulty number. Only using repetitions of heavy grinders once the difficulty value gets large enough.
An example distribution value set might look like this...
What this solution does well, is give good variance on difficulty with the adjustment of a single number. I cannot stress enough that having a single aggregated number that drives the waves difficulty greatly reduces complexity. It avoids the perception of "just throw more enemies at them" and replaces it with variety.
If I were to improve upon this mode, I would tweak the algorithm to allow loadouts to be a part of a given item in the set. That way, difficulty could account for specific loadout combinations.
留言