2019 Mar 10
Fire Emblem CiphAR - Release 2
Release 2 (Store page) has been rolled out to production. Here are the major fixes made/features added:
1) Reduced text jitter considerably. Instead of updating text position every frame, it's now updated every 180 frames. Additionally, when updating position, it now linearly interpolates between the current position and the new position. I also updated the image database used by ARCore with the actual size of the scanned cards, which apparently helps in tracking image targets.
2) Based on feedback, I added a few changes to overlaid text to increase readability. There's now a thin black outline around the rendered text. Additionally, I added a color picker that can be used to change font color.
3) Added some cards that were missing from series 15. There are some other cards that aren't working as well, that are listed below.
From starter decks:
- S01-003ST Loyal Retainer, Jagen
- S02-004ST(+) Steel Swordsman, Ogma
- S04-004ST(+) Leo: Gravity Master
- S06-001ST(+) Itsuki Aoi: Chosen Young Lord
- S06-002ST(+) Tsubasa Oribe: The Pegasus Idol
- S06-004ST(+) Kiria Kurono: Quirky Charisma
- S06-005ST(+) Eleonora Yumizuru: Aiming for Hollywood!
From series:
- B01-006HN Caeda: Princess of Talys
- B01-010N Abel: Green Knight
- B01-047N Tiki: Divine Dragon Princess
- B01-055N Lucina: Sacred Descendant
- B01-056HN Lucina: Swordsman Known as Marth
- B01-079N Nowi: Tomboyish Manakete
- B01-082HN Practitioner of Dark Arts, Tharja
- B01-096N Noire: Bipolar Archer
- B01-099HN Tiki: Sentimental Divine Dragon
- B01-002N Corrin (Male): Hidden Dragon Prince
- B02-005HN Azura: Songstress of the Fountain
- B01-007N Ryoma: First Prince of Hoshido
- B02-009N Hinoka: First Princess of Hoshido
- B02-031N Felicia: Clumsy Maid
- B01-036N Rinkah: Daughter of Fire
- B02-055HN Azura: Songstress of Water
- B02-063N Elise: Princess of the Dark Sky
- B01-036N Charlotte: Lovely Warrior Lady
- B03-017N Rolf: Vendure Brother
- B04-003HN Tsubasa Oribe: Dreaming Schoolgirl
- B04-027N Catria: Swift Whitewing
- B04-053HN Itsuki Aoi: Normal Kid
- B04-059R(+) Eleonora Yumizuru: Precious Actress
- B04-060N Eleonora Yumizuru: Forceful Heroine
- B04-061HN Eleonora Yumizuru: Ambitious Young Actress
- B04-095N Severa: Hesitant Blade
- B04-097N Laurent: Seeker of Truth
- B06-045R Mahnya: Sky-Dancing Hero
- B05-056SR(+) Leo: Dark Prince of Chilling Magic
- B06-059N Elise: Sweet Sister
- B06-068HN Arthur: Knight of Bad Luck
- B06-069N Arthur: Unlucky Hero
- B06-071N Felicia: Refreshing Ice Sister
- B06-032R Raven: Blade of Love and Revenge
- B06-036N Fiora: Pure White Wings
- B06-037N Pent: Silver Mage General
- B06-042N Jaffar: Heartless Assasin
- B07-052N Ryoma: Master Swordsman of Hoshido
- B76-060R(+) Saizo: Garbed in Honor
- B06-073N Jakob: Faithful Staff Knight
- B06-083N Yukimura: Bespectacled Wiseman
- B06-085N Shiro: Prince Polishing his Spearmanship
- B06-087HN Mitama: Sullenly Waking
- B06-099HN Yuzu: Crane Dreadknight
- B08-003HN Chrom: Branded Prince
- B08-007N Robin (Female): The Exalt's Other Half
- B06-032N Morgan (Male): Amnesiac Boy
- B06-036HN Noire: Ballistic Sniper
- B06-037N Noire: A Shot from the Dark
- B06-042N Emmeryn: Compassionate Exalt
- B08-047aN Risen: Defiled Soldier
- B08-047bN Risen: Defiled Soldier
- B08-047cN Risen: Defiled Soldier
- B76-060N Larcei: Gallant Myrmidon
- B06-073N Johalvier: Fighter of Love and Justice
- B06-083HN Ares: The Young Black Knight
- B06-087R(+) Febail: Gallant Divine Marksman
- B06-099N Emma: Kaching Dragon
- B09-014N Kliff: Surly Passion
- B09-018N Lukas: Messenger from the Deliverance
- B06-032N Mathilda: Beautiful Knight
- B06-036HN Catria: Drifting Pegasus Knight
- B06-037N Est: Drifting Youngest Pegasus
- B09-075N Yuzu: Purple-Gleaming Protecto
- B09-093N Mist: Girl of the Mercenaries
- B10-034N Mareeta: The Sword Saint's Flowing Blood
- B06-036SR(+) Tina: Mischievous Saint
- B11-101+X(S04-003ST) Camilla: Bewitching Malig Knight
- B12-015N Soren: Wise Man of the Mercenaries
- B13-096N Princess of Múspell, Laevatein
- B14-012HN Olivia: Soothing Dancer
- B14-055N Azura: Requiem
- B15-012N Roderick: Serene Squire
- B15-021N Catria: Macedonian Pegasus Knight
- B15-022R(+) Palla: Greenwind Dracoknight
- B15-023N Palla: Elder Macedonian Pegasus
- B15-049HN Alice: Dauntless Mounted Princess
- B15-050HN Valjean: Armored Sorcerer
- B15-078SR Altena: Wishing for a Warless World
- B15-079N Altena: Thracian-Raised Princess
I'll work on figuring these out this week. Let me know if there's anything not on the list that isn't working as well.
Programming ciphAR
2019 Mar 09
QMK - Added some songs and note types
I've decided to start adding songs to the QMK song list on a weekly basis (since my music format conversion framework makes it really easy to do).
Here is my weekly commit - I added La Campanella by Liszt, Kataware Doki from Kimi no na wa and Megalovania from Undertale.
I also added the breve note type to musical_notes.h, since the default tempo in QMK is very high, so a higher duration note seemed necessary for a lot of slower songs.
Programming Music Keyboards
2019 Mar 09
Cambiare - A Lightweight Music Conversion Framework
I was messing around with QMK (popular firmware used with mechanical keyboards) a few days ago and was adding custom songs to my Preonic keyboard, and it was taking forever. So I wrote a small utility to convert MusicXML files to a string output format that could easily be added to a QMK song list.
Here's an example input:
Here's an example output:
I later decided to use this utility as the basis of a small framework to convert single staff music inputs into custom outputs, so I could use it for other output types later.
Inputs are modules that implement the MusicImporter abstract class, and outputs must implement the MusicWriter abstract class. The process of adding a new input module mainly consists of converting notes in the input type to a CNote, and adding a new output module mainly consists of converting a CNote into the output format.
The next type of output format I'm planning to implement is for Ocarina tabs, specifically for 12 hole ocarina's with a range of A4-F6.
Github: Link
Programming Music Keyboards
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