2019 Mar 05
Tactics RPG - Element Effectiveness Chart
One major addition I'm making to the normal Tactics RPG formula is adding a Pokemon-esque element effectiveness system. Elements can be attached as a component to any other component, such as a unit, an ability or a weapon.
Here is a (tentative, as always) type effectiveness chart for attacks and unit types:
Here is a sample implementation, where the effectiveness chart is parsed at run-time and written into a static class, so it can be accessed by any other entity in the game scene.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public static class ElementChart {
public static Dictionary<ElementTypes, Dictionary<ElementTypes, float>> elementChart = new Dictionary<ElementTypes, Dictionary<ElementTypes, float>>();
static ElementChart()
{
ParseElementChart();
}
static void ParseElementChart()
{
string readPath = string.Format("{0}/Settings/tactics_rpg_element_chart.csv", Application.dataPath);
string[] readText = File.ReadAllLines(readPath);
string[] elementOrder = readText[0].Split('\t');
for (int i = 1; i < readText.Length; ++i)
ParseElement(readText[i], elementOrder, elementChart);
}
static void ParseElement(string line, string[] elementOrder, Dictionary<ElementTypes, Dictionary<ElementTypes, float>> elementChart)
{
string[] elements = line.Split('\t');
ElementTypes element = (ElementTypes)Enum.Parse(typeof(ElementTypes), elements[0]);
Dictionary<ElementTypes, float> elementDict = new Dictionary<ElementTypes, float>();
elementChart.Add(element, elementDict);
for (int i = 1; i < elements.Length; i++)
{
ElementTypes currentElement = (ElementTypes)Enum.Parse(typeof(ElementTypes), elementOrder[i]);
if (!elementChart[element].ContainsKey(currentElement))
{
elementChart[element].Add(currentElement, float.Parse(elements[i]));
}
}
}
And finally, here is an example implementation of the Element class.
public class Element : MonoBehaviour {
public List<ElementTypes> elements = new List<ElementTypes>();
public void AddElements(List<ElementTypes> elements)
{
this.elements = elements;
}
public float GetTypeMultiplier(List<ElementTypes> defenderElements)
{
float totalMultiplier = 1;
for(int i = 0; i < elements.Count; i++)
{
totalMultiplier *= GetTypeMultiplier(elements[i], defenderElements);
}
return totalMultiplier;
}
public float GetTypeMultiplier(ElementTypes attackerElement, List<ElementTypes> defenderElements)
{
float elementMultiplier = 1;
for(int i = 0; i < defenderElements.Count; i++)
{
elementMultiplier *= ElementChart.elementChart[attackerElement][defenderElements[i]];
}
return elementMultiplier;
}
}
This implementation assumes that the attacking component (whether it's a weapon or an ability) has this Element component attached to it, and the defending unit has an element attached to it as well. The output is then an elementMultiplier, which is calculated as the product of each ElementType in the attackers Element class against each ElementType in the defenders Element.
For example, an attacker with an Element component that has ElementTypes [Fire, Light] against a defender with an Element component that has ElementTypes [Water, Dark] would result in calculation ElementChart[Fire][Water] * ElementChart[Fire][Dark] * ElementChart[Light][Water] * ElementChart[Light][Dark] = 0.5 * 1 * 1 * 2 = 1.
Programming TacticsRPG
2019 Mar 05
Tactics RPG - Experience
Right now, experience is rewarded as a weighted amount based on a units level to the entire party. VERY temporary, I don’t like it. It seems like it would make it way too easy to have a balanced party, and way too easy to raise new units. However, I also don’t want to have the fire emblem issue where you get a bunch of potentially good units that become useless because you have no way of raising them (besides grinding, which should probably also be discouraged). Potential ideas:
-
Some kind of pair up system, similar to Awakening/Fates, where a paired unit gets some share of the EXP when the main unit gets a kill (only the main unit and the paired unit get exp)
a) Not sold on this, since the unit getting the EXP doesn’t really have to do much
b) Also runs into the “chaperone” problem, feels similar to escort missions
c) If implemented, would need to be balanced REALLY well
-
Some external ways of getting exp? Would need to be very limited, but would probably also have to scale based on where the player is in the game/the levels of their other units maybe?
-
An item allowing a unit holding it to share exp
a) Similar to the EXP share (old version) in Pokemon b) Again, feels a bit too easy c) There would probably need to be a heavy downside to using it (ie. cannot move, cannot attack, lowered defense maybe)? But these downsides seem to de-incentivize combat, which I probably don’t want.
-
NOT “last hit” based
a) I like this. Basically, instead of having EXP given to a unit just because they got the killing blow, it should be awarded based on the units who actually damaged the enemy b) Equally to all units? Based on damage dealt? Based on level? Honestly not too sure. c) Downsides - this seems like it might make it harder to raise weaker units, unless it’s made to be level based. But, if it’s level based, it makes it harder to prioritize units you really like (unless you make them the sole unit participating in that combat, which kind of seems like it would exacerbate the issue of having useless units). Either way, this is a trade off that needs to be carefully balanced.
Currently, I’m leaning towards something like this example:
- Units involved in combat: Lvl 10, 5, 1, 1
- Enemy unit killed: Gives 100 xp
- Total levels = 10 + 5 + 1 + 1 = 17
- Weighted amounts = 10/17, 5/17, 1/17, 1/17
- 1 - weighted amounts = 7/17, 12/17, 16/17, 16/17
- Easing values = map(lambda x: easing_function(minlvl, maxlvl, (total_lvl-x) / total_lvl, 1-weighted_amounts list)
- Eased total = sum of easing values
- Eased lvl percents = map(lambda x: x / eased total, easing values)
- Eased exp values = map(lambda x: exp amount * x, eased lvl percents)
- In the given example: a) Easing values = [8.9, 8.9, 5.5, 2.5] for [1,1,5,10] b) Eased total = ~25.8 c) Eased lvl percents = [.344,.344,.212,.097] d) Eased exp values = [34.4, 34.4, 21.2, 9.7]
Programming TacticsRPG
2019 Mar 05
Tactics RPG - Stats and Levels
Shifting gears a little bit from the last post, I'd like to go over characters stats and levels a bit.
Stats
Copied from the enum:
public enum StatTypes {
LVL, // Level
EXP, // Experience
HP, // Hit points
MHP, // Max Hit points
MP, // Magic Points
MMP, // Max Magic Points
SP, // Skill points
MSP, // Max Skill points
INT, // Intelligence
ACC, // Accuracy
ATK, // Attack
DEF, // Defense
MAG, // Magic attack
RES, // Magic resistance
EVD, // Evasion
SPD, // Speed
LCK, // Luck
MOV, // Movement range
JMP, // Jump Height
}
These aren’t final, just some rough ideas I had during development:
Level
Level is, obviously, tied to experience. Currently using the Ease In Quad formula, such that:
- (0, max experience and level percent) are input arguments
- Level percent is Mathf.Clamp01((float)(level - minLevel) / (float)(maxLevel - minLevel));
- Max level is 99
- Min level is 1
Not set in stone, just a basic placeholder until I decide on something else Mainly contained in Rank.cs
Programming TacticsRPG
2019 Mar 02
Tactics RPG - Game board representation
One of the most important things to take into consideration when developing a Tactics RPG is the board representation, since almost every other component in your game will have to interact with it in some way.
In my game, a board is composed of individual Tiles. Each Tile has its own attributes, such as its Tile Type, material and texture. In addition, tiles also maintain a reference to the content placed on top of them, such as a player unit, enemy unit or item.
We define a Point on the board as an x,y,z coordinate. It should be noted that here, the y coordinate of the point actually corresponds to the z coordinate in Unity.
Finally, we represent a Board as a Dictionary that maps a Point to a Stack of Tiles. This representation allows me to have multiple Tiles stacked on top of each other on the same Point, while also giving me access to the top Tile on a Point in constant time. This is important for various functions in the game, such as path finding and movement. Having a stack of tiles with potentially different types allows for various interesting mechanics involving terrain transformation, such as terrain destruction and building.
One further optimization made to the above board representation is, if two of the same types of tile are stacked on top of each other, to increase the height of the base tile instead of stacking the two tiles on top of each other. This way, if you have a relatively homogeneous board (ie. a lot of the same tile type), instead of having to render a new Tile for each Tile in a particular Stack, you can instead have a single Tile but with a height equal to the total number of Tiles at that Point multiplied by the height per tile. To put this in perspective, suppose you have a 10 by 10 by 10 board where every Tile is of type Grass. If the board is full and you render a Tile per Point, you would have to render a total of 10 * 10 * 10 = 1000 tiles. Alternatively, using the optimization described above, since each Point would technically only be rendering one Tile, we would only have to render 10 * 10 = 100 Tiles.
Here is an example board creating using the above board representation in my board editor. It also includes some background assets (water, rocks), as well as environment assets placed on Tiles, such as trees and lights.
Programming TacticsRPG
2019 Mar 02
Tactics RPG Project - Introduction
I've been working on a Tactics RPG game for a few months now, and decided writing about it would help keep me motivated and might bring in some new ideas. So here I am. Writing about it.
A lot of this project is based on the excellent tutorial on TheLiquidFire's Blog, where he details how to implement a Tactics RPG with heavy inspiration taken from Final Fantasy Tactics. I enjoy a lot of mechanics from Fire Emblem as well, so I decided to base the mechanics of my game around both Fire Emblem and FF Tactics.
This isn't meant as a tutorial or a project to program along with - I'll mainly be detailing the high level mechanics of various systems in the game, along with an occasional code snippet. At best, maybe something I write about here will be applicable or inspire something in one of your own projects.
Programming TacticsRPG