A fellow user on Reddit asked us a couple of questions about us, inspiration and the development process of Reynard. So I’ve decided to write a more general article… Let’s call it “Reynard – Road To Early Access.”
TL;DR;
We used Unity3D and the C# language. We were inspired by the wish of making our own video game and were influenced by games as Final Fantasy, Legend Of Zelda: A Link To The Past, Warcraft 3 TD maps and Binding Of Isaac. Technically we started developing Reynard on 6th of October 2017 – that’s the date of my first “pet project” commit on git. Project was originally called “Into The Fray”. We’ve been working on a couple of games earlier, but we never developed anything this “big”. Our advice for aspiring game developers would be: “Start small, set smaller milestones and finish what you’ve started”.
Game engine we used
We developed Reynard in Unity3D engine using C# language. The engine itself is fantastic, but when we started we wrestled with pixel perfect camera, tile extrusion and so on. Maybe if we picked an alternative such as Godot we’d avoid these problems, but then again we were familiar with Unity3D and in the end, it has tons of learning material and a very well equipped asset store.
I also kind of cheered for Unity3D, because there are many employers and project which use it. I wanted to know that even if our games fail, I’ll learn something useful, something that will help me on my developer path in the future.
Inspiration for making video games and Reynard
I will write this from my perspective and I’ll ask Boštjan to add his points of view.
Inner struggles
I had a wish of creating my own video game since I was a kid. But… You know… It is different when you daydream about something and when you decide “I’m gonna do it, or die trying”. Since I didn’t and don’t (yet) have kids and I saved some money that would keep me “alive” for several of months, I decided… I’m gonna do it! I’m gonna pitch an idea to my old school mates.
That’s how it started. For the “test of collaboration” game, we’ve created our first simple mobile game Math Panda. After Math Panda we’ve decided that we’ll try to create a game inspired by Kingdom called Pariah: Anton. In the middle of making Pariah, I gave a proposal for creating one “sprint” match 3 clone – Space Cyclops.
The reason for a sprint was behind me being stuck in the development process and not seeing an exit, I just really had to do something else before I lost my motivation… it was probably too ambitious a project for me back then. So when we finished Space Cyclops we went back on Pariah… and soon I again started working on some other pet projects. The next pet project’s prototype name was called “Into The Fray” which later turned into “Reynard”.
Influences
Reynard has been influenced by many games we played growing up.
When I was a kid my parents bought me my first gaming console, the SNES. The game that came with it was none other than Super Mario World. I immediately fell in love with it. But then you beat your first game and you need something more. Luckily I got Final Fantasy Mystic Quest from my half-brother’s cousin. I couldn’t understand the game because it was in German. But you know, back then I just went with it… even though the game is presented as a “starter RPG” for the European market, I loved it. I really liked its top-down perspective and the art! There was this huge manual that I couldn’t understand but the art in it was amazing and the cover image was epic!
So time goes by… I get a PC and it has the ability to run console emulators… which opens an opportunity to play all other games that I didn’t even know exist for SNES. First I went for Final Fantasy games… Played them all. But then I remembered about the cool looking top-down game my school mate once brought with him to school which we played in a class room (it was a special day in school and not a thing we did every day :D). The things that stuck with me were: no waiting for turns like in Final Fantasy games, cool story and pixel art. The game was none other than The Legend of Zelda: A Link to the Past.
The next game of inspiration was Warcraft 3. Blizzard hit the jackpot with the level editor. You could download thousands of player-made maps and you could play them with your friends! That’s what we did… we played tons of tower defense in Warcraft 3 😀
And Boštjan… He is an Isaac maniac (770+ hours played :D) and we both love its rogulike elements.
Development and larger hurdles
The first commit was on 6th of October 2017… but it was just a prototype… Back then I was working on Pariah. I still dream about finishing that game. Well, anyway… Pariah started to get more complicated, and in my free time I started working on a top-down game. I just wanted to do something else from time to time. Eventually we had a meeting with the team and we decided to switch to another project and start working on a roguelite top down game. We thought that it would be more fun and easier to make… Fun? Sure! Easier!? Not really 😀
Some of the hurdles were:
Not being synced with the team – in the first half of development, I was the only one working on Reynard fulltime. Luckily, Boštjan committed to the project when I needed him the most. Believe me that having someone to discuss matters with is very powerful and keeps you motivated.
Many times we had a working system but sometimes I just didn’t think it was flexible or good enough so I redesigned some of them completely from the ground up even though they were doing their job just fine. I guess the reason behind this was that we never really had a clear picture of what we were building and that I tried to program systems that we’d reuse in future games.
Not having an artist. Learning to draw pixel art was fun but it took a lot of time that I could spend on programming.
Unity importing small assets every save (importing lasts around 10 minutes). Still looking for the root cause of this problem.
If you’re interested you can read some of our devlogs which you can check out here.
Our advice for aspiring game developers
“Start small, set smaller milestones and finish what you’ve started”.
Future
We’re gonna add more content to Reynard and polish it. At the moment I’m working on different merchants, area of effect spells and so on. We’re also starting the process of steam submission.
So if you like what you’ve read and you’re interested what Reynard is all about, you can check it out here:
When Hammlet’s wife Prascilla goes missing, Reynard immediately grabs his high-tech gauntlet and goes on an adventure. In order to rescue Prascilla from becoming “Goulash” and his home island Foen from an invasion, he has to defeat many vicious creatures and villains.
Gameplay
Reynard is a mixture of procedurally generated action RPG and a Tower Defense genre with roguelike elements. It has been influenced by classics such as Legend of Zelda and an indie classic – Binding of Isaac. It contains features such as:Countlessproceduraly generated dungeons, TD maps and runes!
More than 200 different items!
Fast paced action against challenging enemies and bosses!
Progression through perk and blueprint system!
Simple yet cool crafting system!
Lovely story and companions!
Minimum Requirements
Gamepad is extremely recommended, but keyboard also works.
If you’ve been following our blog, you’ve read that we are working on a game called Pariah: Anton. Well… the development did not come to an end, but it reached the point where we took a pause.
Here are couple of reasons for the pause:
I have to finish couple of systems (AI is one of them).
Žiga still has to finish environment and UI art.
Patrick has some song and SFX writing to do.
I can tell that my motivation dropped because I’ve been working on a codebase for a long time. And the biggest reason for the motivation drop is a lack of vision of a finished game. I’ve reached a point where I couldn’t visualize the end game and that made me very frustrated.
The team had a meeting where we discussed the future of the game and how we’ll implement some stuff to finally finish it. A couple of days before that meeting I’ve shown guys a prototype I’ve been working on… And because prototype seemed cool… On a meeting, we decided to start and finish that prototype before finishing Pariah.
The prototype – Reynard
Sometimes when I have no willpower to work on certain projects, I start prototyping and designing other stuff. Which certainly isn’t a pattern that many other developers face. As a fan of Hyper Light Drifter, Final Fantasy and Zelda games, I knew that sooner or later I’ll open Unity3D and start working on my own version of a top-down game.
It actually happened… and unlike other times when I keep prototypes for myself, I showed it to my friends in hyper fox studios.
It is a very basic prototype of a top-down game, but it directed us on a new path. To keep me motivated to the end of the project, I’ve decided to post an update on a Reynard game every Friday! Follow us on social media to stay tuned!
Many games like Diablo, World of Warcraft and Final Fantasy use loot drop tables for… well… amm… loot drops and stuff 😀
Currently in Pariah I’m facing random generation. Even though it’s gonna be “randomly” generated world, I still want to have some kind of control over the quantity of spawned items, randomly picked backgrounds, vegetation, resources etc.
I’m not saying that the way I’m doing it, is the best way to implement control over randomness, but I found out that using loot drop table (LDT) can really help me out in multiple situations.
Example of usage
For example we can use loot drop tables in biomes when we want to generate ground. Ground can be made out of different tiles, but we still want to pick the tile with the most grass in it and use it more frequently than other tiles… and that’s where we can harness the power of loot drop tables.
We can create a treasure chest script, that has chances of dropping rare, frequent or maybe legendary loot.
We can use loot drop tables for all sorts of stuff. Before diving into the code and further explanation, I’d really recommend reading this awesome article about loot drop tables on Gamasutra.
The case, tutorial and our goal
I know that i’m gonna use loot drop tables multiple times for different scenarios and that’s the reason why I decided to write two simple generic classes that implement basic loot drop tables and loot drop items (LDI) on which we can extend and build more complex systems.
Goal
In Unity we want to have a “GameObject” or a “ScriptableObject” whose script can contain a loot drop table type property. Loot drop table will give us the ability to add items to it’s list, assign item’s probability and randomly pick them based on their weight.
For example, loot drop item can be an enemy that will be spawned in certain area, a rare or a common sword which the player can acquire from treasure chest, an integer which represents the tile id in our tilemap… or whatever we want it to be.
Also we want to have a control over probability of this item being picked by our loot drop table script and here’s the reason we want to assign a weight to each item separately. Weight in our case is nothing else but an integer. Higher the integer, higher the chances of item being picked.
We’re gonna create a “treasure chest” which will “spawn” different items each time we start the game. We will have the ability to assign which item can spawn and what is it’s probability / weight.
About logic in our loot drop table
Our LDT script combines items to a list, ads up items weights and based on weight’s sum, sets the ranges to which the item belongs. LDT script then picks a random number from “0 – sum of all item weights” and based on that randomly selected number, picks the item.
Example
Total weight of 2 items is 120. Weight of first item is 50 and weight of second item is 70. Based on their weights, LDT assigns that the first item belongs to a range 0-50 and the second item belongs to a range 50-120. Based on these numbers, LDT then picks a random number between 0 and 120. If it picked a number which is for example “76”, it means that the second item was picked. Now that we know which item was picked, we can do whatever we want with it.
For better understanding what’s happening, check out the video above.
So in the end we want to create 2 abstract classes (genericLootDropItem.cs and genericLootDropTable.cs) which can represent different value types. Then we can inherit different variations of LDTs and LDIs by passing them a type. In our case, we’re gonna create an GameObject variation of LDT and LDI.
Because they can represent different values, I saw a solution in using generics. If you aren’t familiar with generics, you can check out this cool tutorial about generics made by Brackeys.
The code
When writing “nested” generic code, the biggest “problem” I’ve encountered was the inablity to assign the items to a LDT via Unity’s inspector. In my understanding the “problem” is that unity can’t serialize generic properties which are multiple level deep.
One of the consequence is that these properties don’t show up in the inspector and we can’t assign them via inspector even if the code is without an error.
My workaround for this problem is that we create an abstract generic class for LDT and LDI from which we inherit other classes based on the type we want to use. This way we “trick” Unity in a way that it show’s up properties in the inspector and we don’t have to write a lot of code over and over again.
GenericLootDropItem script
Let’s start by writing the most basic element of our system, which is a GenericLootDropItem:
It holds information about the item it represents.
It has weight.
For information purposes it displays item’s chance of being picked (in percents).
It holds information about the range it belongs to.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Item that can be picked by a LootDropTable.
/// </summary>
public abstract class GenericLootDropItem<T>
{
// Item it represents - usually GameObject, integer etc...
public T item;
// How many units the item takes - more units, higher chance of being picked
public float probabilityWeight;
// Displayed only as an information for the designer/programmer. Should not be set manually via inspector!
public float probabilityPercent;
// These values are assigned via LootDropTable script. They represent from which number to which number if selected, the item will be picked.
[HideInInspector]
public float probabilityRangeFrom;
[HideInInspector]
public float probabilityRangeTo;
}
After we know how our item looks like, we can continue with writing GenericLootDropTable script.
GenericLootDropTable script
It’s the brain of our loot drop table system.
Contains a list of LDIs.
Holds information about total weight of all LDIs.
It has a method which validates all of assigned LDIs (set’s their range from, range to, calculates percents).
It also has a method which returns the “randomly” picked LDI from it’s list.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Class serves for assigning and picking loot drop items.
/// </summary>
public abstract class GenericLootDropTable<T, U> where T : GenericLootDropItem<U>
{
// List where we'll assign the items.
[SerializeField]
public List<T> lootDropItems;
// Sum of all weights of items.
float probabilityTotalWeight;
/// <summary>
/// Calculates the percentage and asigns the probabilities how many times
/// the items can be picked. Function used also to validate data when tweaking numbers in editor.
/// </summary>
public void ValidateTable(){
// Prevent editor from "crying" when the item list is empty :)
if(lootDropItems != null && lootDropItems.Count > 0){
float currentProbabilityWeightMaximum = 0f;
// Sets the weight ranges of the selected items.
foreach(T lootDropItem in lootDropItems){
if(lootDropItem.probabilityWeight < 0f){
// Prevent usage of negative weight.
Debug.Log("You can't have negative weight on an item. Reseting item's weight to 0.");
lootDropItem.probabilityWeight = 0f;
} else {
lootDropItem.probabilityRangeFrom = currentProbabilityWeightMaximum;
currentProbabilityWeightMaximum += lootDropItem.probabilityWeight;
lootDropItem.probabilityRangeTo = currentProbabilityWeightMaximum;
}
}
probabilityTotalWeight = currentProbabilityWeightMaximum;
// Calculate percentage of item drop select rate.
foreach(T lootDropItem in lootDropItems){
lootDropItem.probabilityPercent = ((lootDropItem.probabilityWeight) / probabilityTotalWeight) * 100;
}
}
}
/// <summary>
/// Picks and returns the loot drop item based on it's probability.
/// </summary>
public T PickLootDropItem(){
float pickedNumber = Random.Range(0, probabilityTotalWeight);
// Find an item whose range contains pickedNumber
foreach (T lootDropItem in lootDropItems)
{
// If the picked number matches the item's range, return item
if(pickedNumber > lootDropItem.probabilityRangeFrom && pickedNumber < lootDropItem.probabilityRangeTo){
return lootDropItem;
}
}
// If item wasn't picked... Notify programmer via console and return the first item from the list
Debug.LogError("Item couldn't be picked... Be sure that all of your active loot drop tables have assigned at least one item!");
return lootDropItems[0];
}
}
You might ask yourself why we’re not inheriting this class from MonoBehaviour and not validating the LDIs in OnValidate method. I’ll explain the reason in the lower section 🙂
Now that we have base generic classes, we can create LDT and LDI for GameObject type.
GenericLootDropItemGameObject script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// When we're inheriting we have to insert GameObject as a type to GenericLootDropItem
/// </summary>
[System.Serializable]
public class GenericLootDropItemGameObject : GenericLootDropItem<GameObject> {}
GenericLootDropTableGameObject script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// When inheriting first we have to insert GenericLootDropItemGameObject instead of T and a GameObject instead of U
/// </summary>
[System.Serializable]
public class GenericLootDropTableGameObject : GenericLootDropTable<GenericLootDropItemGameObject, GameObject>{}
TreasureChest script
It’s the script that represents the treasure chest itself. For the tutorial’s purpose we’re gonna try to keep it as simple as possible. It’s main goal is:
When the game starts it picks and generates items from it’s LDT property.
Validates LDTs and LDIs.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// The most simple treasure chest script ever made :P basically on game start it spawns items in a straight line.
/// </summary>
[System.Serializable]
public class TreasureChest : MonoBehaviour {
// Loot drop table that contains items that can spawn
public GenericLootDropTableGameObject lootDropTable;
// How many items treasure will spawn
public int numItemsToDrop;
// Runs when we start our game
public void Start(){
// Spawn objects in a straight line
DropLootNearChest(numItemsToDrop);
}
void OnValidate(){
// Validate table and notify the programmer / designer if something went wrong.
lootDropTable.ValidateTable();
}
/// <summary>
/// Spawning objects in horizontal line
/// </summary>
/// <param name="numItemsToDrop"></param>
void DropLootNearChest(int numItemsToDrop){
for (int i = 0; i < numItemsToDrop; i++)
{
GenericLootDropItemGameObject selectedItem = lootDropTable.PickLootDropItem();
GameObject selectedItemGameObject = Instantiate(selectedItem.item);
selectedItemGameObject.transform.position = new Vector2(i/2f, 0f);
}
}
}
Because this script unlike GenericLootDropTable inherits from MonoBehaviour, It also has a role for validating LDTs and LDIs. Basically it calls LDT’s ValidateTable method in OnValidate method which validates values as soon as we assign them in the inspector.
The main reason for calling LDT’s ValidateTable method inside the TreasureChest script is that if we inherit the GenericLootDropTable from MonoBehaviour we don’t see LDI’s exposed properties.
If GenericLootDropTable inherits from MonoBehaviour
If GenericLootDropTable doesn’t inherit from MonoBehaviour
Now that we have every script we need, we can easily recreate the demo scene from the video.
Summary
Our loot drop table belongs to more “primitive systems” out there 😀 It can be improved and modified in many ways. Here’s the link to my github repo from where you can easily download unity package and test it out yourself.
What I really like about our simple system is that for an example we could really quickly create LDT and LDI of an integer type and modify our treasure chest script in a way that besides dropping items, it would also drop golden coins or something else.
This is my first tutorial and I hope that some of you will find it helpful. If any of you fellow readers have a suggestion, or have an idea on what I could improve, or if you noticed a bug, please let me know in the comments down below.