Kikai is an idle merger game which involves passive resource generation through the monsters in the world. The resource generation rate is improved by merging monsters to create a new monster. There are multiple worlds each featuring their own set of monsters, abilities and effects which help to augment the gameplay loop of achieving a bigger gold generation.
This game was started to experience a full game development cycle and understand my weak points and what I enjoy in game development. I sought to build a small game to ensure that I would see the project to completion, and for this reason I chose to build a mobile game.
Over the years I have briefly idle games and enjoyed the gameplay loop of making a number bigger. The main inspiration for deciding on an idle merger was a game called Evolution Galaxy: Mutant Merge. I particularly enjoyed the loop of merging creatures to see what the next creature looks like. What gave me the push to attempt this gameplay was that while I enjoyed the game I was constantly frustrated with the user interface and ads popping up frequently upon changing world or screen.
A system which is capable of reading the correct data across different gameplay aspects (abilities, boosts, resource generation, etc.) and rewarding the player upon completing the objective’s criteria.
There are multiple worlds for the player to manage, each with their unique monsters, objectives and abilities alongside an effect which helps to augment the gameplay.
The player can use the patterns they earned to change the visual appearance of the monsters.
Each world has a unique set of abilities which the player can activate to improve their resource generation.
A class capable of storing larger numbers than what is capable by a decimal variable.
The gameplay involves the player using their gold to buy monsters, and then merging the same monster to create a better monster which is capable of producing more gold per second. Therefore the gameplay loop is buying monsters with gold to generate more gold. As the player unlocks new monsters they will unlock abilities which will help them in their goal of producing more gold.
Apart from the gameplay loop of buying monsters, the player is also to reset the world in which their gold and monsters are reset in exchange for a currency which they can spend to upgrade their world and abilities. The currency received is based on the total amount of gold generated. The world upgrades will improve the player’s gold generation, and reduce monster costs while the ability upgrades will improve the strength of the ability and reduce its cooldown. Upon purchasing all the upgrades available within the world the player is given the option to prestige the world. Doing so will reset all currencies, monsters and upgrades in exchange for a permanent buff to gold generation.
To reward and motivate the player to keep engaging with the gameplay loop there are patterns for the player to collect which can be used on monsters to change their appearance. These are obtained by fulfilling objective criteria which range from sacrifice X monsters using the sacrifice ability to prestige the world X times. This is intended to motivate the collector player archetype in playing the game.
There are multiple worlds for the player to manage, the intention is to have these worlds unlock gradually to help break up the repetitive nature of the idle game. Each world after World One has an effect which seeks to make the player engage with the gameplay in a different manner, alongside abilities which interact with these effect.
The goal of the abilities is to provide a boost to the player’s goal of obtaining gold. My mindset when designing an ability is as follows:
Below is a breakdown of the abilities usable in World One.
This ability will periodically merge monsters with a chance to perform a super merge in which the monster will skip a rank.
This is the first ability the player unlocks and therefore was kept simple. Involving no work on the player’s end except for ensuring that there are monsters capable of being merged.
Applies a bonus to gold generation, merging during this bonus will increase the duration and strength of the bonus.
This ability maintains the simple nature of ensuring there are monsters ready to be merged during the ability to maximise the gains. This ability pairs well with the previous ability (Auto Merge) while still keeping the decision-making process simple.
Reassigns a random new rank to all monsters in the world, with a chance to roll the highest discovered rank while protecting the player’s highest-ranked monster in the world from being rerolled. This ability can be reactivated several times for a short period after first being activated.
This ability sees the player risking their monsters’ ranks to obtain a new set of monsters with different ranks which may be higher. The ability to reactive the ability allows the player to make merges based on these new ranks and then try their luck again. By itself, this ability already injects a fresh decision-making process for the player but pairing this ability with the previous ability (Gold Multiplier) we see this shine. Now the gameplay is about rerolling and not necessarily caring about the monsters’ ranks but instead about obtaining pairs which can be merged to obtain the benefits of the active Gold Multiplier ability.
The player can select several monsters to remove in exchange for a burst of gold equal to the sacrificed monsters’ gold generation for X hours.
The last ability for World One is more standalone ability with no intentional combo with the previous abilities. The intention is to give the player the choice of being able to receive a short-term benefit (burst of gold) at the cost of possibly missing out on long-term benefits (losing a monster) should they not replenish the monsters lost. This could be used to accelerate the purchasing of a particular monster or to gain a burst of gold before resetting which will increase the amount of currency received for resetting.
The player can select a monster and then a specific body part from that monster in which to apply a pattern to fill that body part. Any changes are applied by spawning a game object off-screen which is split into the individual body parts of the monster, with each part being a sprite mask and filling the mask with pattern’s sprite. To avoid sprites and masks being mixed up involved placing them on different layer orders. The sprite is set to the pattern, this pattern would contain data such as the SpriteDrawMode so it knows how to handle filling the full extent of the sprite.
Then a Texture2D screenshot is taken and converted to a sprite and saved locally. This sprite is what is used to show the monster to the player. By using one sprite instead of a game object which is drawing the monster each time it was possible to show the monster in UI elements without having to create an exception which can handle drawing the monster but using UI elements instead of world elements.
When first planning the customisation feature of the game, I intended on having more customisation options in the form of hats/clothing the player could place on top of their monsters. This would have added another layer of customisation and helped keep the reward pool interesting, instead of only rewarding patterns. I ultimately decided to not implement this due to it requiring a large number of unique drawings, which is not my focus for this game.
To reward and motivate the player to keep engaging with the gameplay loop there are patterns for the player to collect which can be used on monsters to change their appearance. These are obtained by fulfilling objective criteria which range from sacrifice X monsters using the sacrifice ability to prestige the world X times. This is intended to motivate the collector player archetype in playing the game.
Apart from the gold generation number increasing this game seeks to attract achievers. This is being promoted through objectives which award patterns which the player may choose to stick with the game and attempt to collect all the patterns from a given world. Each world has its own objectives which reward the player for performing merges, using abilities, activating boosts, prestige, etc.
The objectives are ScriptableObjects with the different objective types inheriting from the base abstract class. Every objective has a name, and type, whether it uses the lifetime statistics or session statistics and the reward/s for completing. Each objective type overrides three methods to determine the progress (returns a float between 0 and 1), description (returns a custom text string which can handle displaying images in the text) and lastly the progress text (returns the custom text string). When starting up a world the WorldManager checks which objectives are still in progress and places a reference to that objective in a dictionary separated based on objective type. This way when for example a merge is performed only the merge-based objectives are checked. The progress of these objectives are obtained through the world’s statistics data.
Various statistics are being tracked which are split into session and lifetime. The session statistics are reset after a world reset or prestige while lifetime includes everything since the player first started playing the game. Each world has its own WorldStats class which contains variables such as monsters owned, bought and merged. Tracking the statistics for abilities and boosts involved having a base class which is inherited by the class made for each ability and boost. Each has its class due to the data which is being tracked varying from one another.
There are checks called when getting or setting a statistic to ensure that the statistic is not blank or that it exists in the dictionary. Should it not exist then a blank statistic is created, this makes it possible to be able to freely change the abilities in the world, or add additional boosts and abilities to the world without having to worry about breaking the player’s statistics.
The player can continue generating gold even when they are offline, as is common for idle games. On the surface this may appear to be simply a calculation of the time gone multiplied by the gold generation per second. In the case of Kikkai there are abilities and effects which need to be simulated to obtain an accurate offline generation. The process involves iterating through the world’s effects and having each effect determine when its next action should occur. Then performing the action which is soonest to occur from when the player went offline. This process iterates until the next action goes beyond the present time.
Currently, the game is not simulating the abilities, but the framework is already there and I just need to add the logic for each ability on how it should simulating itself. I also need to ensure that the abilities are still able to affect one another during the simulation.
As a part of experiencing the whole game development cycle I made an effort to utilise Unity’s Gaming Services and implemented anonymous login, In-App Purchases and ads. It was my first time working with these services and my goal was to ensure that the classes I created would be reusable for future games I am interested in starting. Therefore there is a class which handles initialising the Unity services with each service having its own class which performs the initialisation for that services alongside that service's functions. An example of this is the Ad service class calling triggering an event when an ad fails, and having the elements which need to react to this subscribed to the event. This approach made it possible to reduce the repeating of IronSource methods while ensuring the logic of IronSource is all in one place.
When adding a large number every second to another number it is inevitable that one will reach the 128-bit limit found in the decimal data type. I did not want to be constantly resetting the player’s numbers as I felt this takes away the progression of an idle game and striving to reach new heights. Therefore to be able to handle bigger numbers I took the approach of making a class which stores the numbers in a list.
Each index stores 3 significant figures, then upon reaching 1,000 that element is set to 0 while the next index has 1 added its value. Therefore an array of [39, 502, 1] represents the number 1,502.039.
It is not enough to store the number I also need to be able to apply arithmetic operations without needing to convert to a decimal, as this would defeat the purpose of this custom class. Therefore I implemented method which make it possible to add, subtract, multiply, rough division and compare which number is greater.
Copyright © 2024 Kooldiagon - All Rights Reserved.
Powered by GoDaddy