So, for a sort of JRPG-inspired game I’m making, I’m designing an enemy class. I have several scripts which I’ve adapated from my Inventory script. The Inventory script works the way I want it to (Grouping items, duplicates doing the same thing) but I don’t know how to adequately change it for the sake of my enemy databse so that when I spawn monsters from the class to a list, they’re all unique, so that if I damage them the damage isn’t shared.
So if I load four slime monsters into my scene, and trigger damage, all of them get damaged instead of the one I’ve specified, despite them all being separate entries in my list.
Below are my scripts. Cobbled together via google-fu and probably some very dumb ideas of mine since I’m not really much of a coder.
Base enemy class script;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class Enemy
{
public int id;
public int enemyNumberInBattle;
public int hp;
public string name;
public string description;
public GameObject enemyPrefab;
public bool isAlive;
public Dictionary<string, int> stats = new Dictionary<string, int>();
public Dictionary<string, int> attacks = new Dictionary<string, int>();
//======================================DEFINITION======================================\\
public Enemy(int id, int enemyNumberInBattle, string name, int hp, string description, bool isAlive, GameObject enemyPrefab,
Dictionary<string, int> stats, Dictionary<string, int> attacks)
{
this.id = id;
this.enemyNumberInBattle = enemyNumberInBattle;
this.name = name;
this.hp = hp;
this.description = description;
this.isAlive = isAlive;
this.enemyPrefab = Resources.Load<GameObject>("Enemies/" + id);
this.stats = stats;
this.attacks = attacks;
}
public Enemy(Enemy enemy)
{
this.id = enemy.id;
this.enemyNumberInBattle = enemy.enemyNumberInBattle;
this.name = name;
this.hp = enemy.hp;
this.description = enemy.description;
this.isAlive = enemy.isAlive;
this.enemyPrefab = Resources.Load<GameObject>("Enemies/" + id);
this.stats = enemy.stats;
this.attacks = enemy.attacks;
}
}
Enemy Database script;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyDatabase : MonoBehaviour
{
public List<Enemy> enemies = new List<Enemy>();
private void Awake()
{
BuildDatabase();
}
public Enemy GetEnemy(int id)
{
return enemies.Find(enemy => enemy.id == id);
}
public Enemy GetEnemy(string enemyName)
{
return enemies.Find(enemy => enemy.name == enemyName);
}
void BuildDatabase()
{
enemies = new List<Enemy>()
{
// ORDER: "ID" (Can't be 000 or 010, must be 0 or 10), "ID IN BATTLE (For selecting")"NAME", "HP", "CURRENT HP" "DESCRIPTION", "IsAlive", "Prefab (ADD ID AGAIN AFTER THE + because for some reason defining it like that in the other script isn't working. figure this out later, future me.)" "stats[]" "attacks[]"
//===================== SLIME ===================== //
new Enemy(0, 0, "Slime", 500, "A simple blue slime. It wiggles.", true, Resources.Load<GameObject>("Enemies/" + 0),
//STATS
new Dictionary<string, int>
{
{"ATK" , 25},
{"DEF" , 25},
{"Max HP" , 500},
},
//ATTACKS ("Name", "ID")
new Dictionary<string, int>
{
{"Attack" , 001},
{"Wiggle" , 002},
{"Consume" , 003},
}),
};
}
}
And here’s the active script in the scene that I use to spawn, damage, destroy and list enemies;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BattleScene : MonoBehaviour
{
public bool SpawnSlime = false;
public bool HurtEnemy1By100hp = false;
public bool HurtEnemy2By100hp = false;
public EnemyDatabase enemyDatabase;
public List<Enemy> battleEnemies = new List<Enemy>();
public GameObject[] EnemyPrefabs;
public GameObject[] SpawnLocations;
private GameObject SpawnPoint1;
private GameObject SpawnPoint2;
private GameObject SpawnPoint3;
private GameObject SpawnPoint4;
private GameObject SpawnPoint5;
public GameObject EnemyParent;
public GameObject Enemy01;
public GameObject Enemy02;
public GameObject Enemy03;
public GameObject Enemy04;
public GameObject Enemy05;
// Start is called before the first frame update
void Start()
{
if (SpawnLocations[0] != null)
{
SpawnPoint1 = SpawnLocations[0];
}
if (SpawnLocations[1] != null)
{
SpawnPoint2 = SpawnLocations[1];
}
if (SpawnLocations[2] != null)
{
SpawnPoint3 = SpawnLocations[2];
}
if (SpawnLocations[3] != null)
{
SpawnPoint4 = SpawnLocations[3];
}
if (SpawnLocations[4] != null)
{
SpawnPoint5 = SpawnLocations[4];
}
}
// Update is called once per frame
void Update()
{
if (SpawnSlime == true)
{
SpawnEnemy(000);
SpawnSlime = false;
return;
}
if (HurtEnemy1By100hp == true)
{
battleEnemies[0].hp = battleEnemies[0].hp - 100;
HurtEnemy1By100hp = false;
return;
}
if (HurtEnemy2By100hp == true)
{
battleEnemies[1].hp = battleEnemies[1].hp - 100;
HurtEnemy2By100hp = false;
return;
}
for (int i = 0; i < battleEnemies.Count; i++)
{
if (battleEnemies[i].hp < 0 )
{
Debug.Log("i is " + i);
battleEnemies[i].isAlive = false;
//Destroy(battleEnemies[i].GameObject);
RemoveEnemy(i);
//battleEnemies.RemoveAt(i); // Remove it. Our list resized, so...
i--; // step back. Next loop iteration will check correct member of array.
Debug.Log("Enemy dies!");
}
else if (battleEnemies[i].hp == 0)
{
Debug.Log("i is " + i);
battleEnemies[i].isAlive = false;
RemoveEnemy(i);
//battleEnemies.RemoveAt(i); // Remove it. Our list resized, so...
i--; // step back. Next loop iteration will check correct member of array. (Thanks person on google for these handy notes.)
Debug.Log("Enemy dies!");
}
}
}
public void SpawnEnemy(string enemyName)
{
Enemy enemyToAdd = enemyDatabase.GetEnemy(enemyName);
battleEnemies.Add(enemyToAdd);
var NewEnemy = Instantiate(enemyToAdd.enemyPrefab);
NewEnemy.transform.SetParent(EnemyParent.transform);
if (battleEnemies.Count == 1)
{
NewEnemy.transform.position = SpawnPoint1.transform.position;
NewEnemy.tag = "Enemy01";
enemyToAdd.enemyNumberInBattle = 1;
Enemy01 = NewEnemy;
}
if (battleEnemies.Count == 2)
{
NewEnemy.transform.position = SpawnPoint2.transform.position;
NewEnemy.tag = "Enemy02";
enemyToAdd.enemyNumberInBattle = 2;
Enemy02 = NewEnemy;
}
if (battleEnemies.Count == 3)
{
NewEnemy.transform.position = SpawnPoint3.transform.position;
NewEnemy.tag = "Enemy03";
enemyToAdd.enemyNumberInBattle = 3;
Enemy03 = NewEnemy;
}
if (battleEnemies.Count == 4)
{
NewEnemy.transform.position = SpawnPoint4.transform.position;
NewEnemy.tag = "Enemy04";
enemyToAdd.enemyNumberInBattle = 4;
Enemy04 = NewEnemy;
}
if (battleEnemies.Count == 5)
{
NewEnemy.transform.position = SpawnPoint5.transform.position;
NewEnemy.tag = "Enemy05";
enemyToAdd.enemyNumberInBattle = 5;
Enemy05 = NewEnemy;
}
return;
}
public void SpawnEnemy(int enemyId)
{
Enemy enemyToAdd = enemyDatabase.GetEnemy(enemyId);
battleEnemies.Add(enemyToAdd);
var NewEnemy = Instantiate(enemyToAdd.enemyPrefab);
NewEnemy.transform.SetParent(EnemyParent.transform);
if (battleEnemies.Count == 1)
{
NewEnemy.transform.position = SpawnPoint1.transform.position;
NewEnemy.tag = "Enemy01";
enemyToAdd.enemyNumberInBattle = 1;
Enemy01 = NewEnemy;
}
if (battleEnemies.Count == 2)
{
NewEnemy.transform.position = SpawnPoint2.transform.position;
NewEnemy.tag = "Enemy02";
enemyToAdd.enemyNumberInBattle = 2;
Enemy02 = NewEnemy;
}
if (battleEnemies.Count == 3)
{
NewEnemy.transform.position = SpawnPoint3.transform.position;
NewEnemy.tag = "Enemy03";
enemyToAdd.enemyNumberInBattle = 3;
Enemy03 = NewEnemy;
}
if (battleEnemies.Count == 4)
{
NewEnemy.transform.position = SpawnPoint4.transform.position;
NewEnemy.tag = "Enemy04";
enemyToAdd.enemyNumberInBattle = 4;
Enemy04 = NewEnemy;
}
if (battleEnemies.Count == 5)
{
NewEnemy.transform.position = SpawnPoint5.transform.position;
NewEnemy.tag = "Enemy05";
enemyToAdd.enemyNumberInBattle = 5;
Enemy05 = NewEnemy;
}
return;
}
public void RemoveEnemy(int id)
{
Enemy enemy = CheckForEnemy(id);
if (enemy == null)
{
Debug.Log("You're trying to remove something that does not exist! (Would you prefer a NullRef error?)");
return;
}
if (enemy != null)
{
battleEnemies.Remove(enemy);
Debug.Log("Enemy Removed: " + enemy.name);
}
else
{
Debug.Log("Failed to remove " + enemy.name + "! What the crap?! Item is appearing as " + enemy + "! Fix that!");
}
}
public Enemy CheckForEnemy(int id)
{
Debug.Log("Searching for enemy...");
return battleEnemies.Find(enemy => enemy.id == id);
}
}
Apologies for the overly complicated script just above. I’m trying to figure out how to PROPERLY TIE each and every spawned prefab to the assigned monster in the list so that I can adequately have the player select between them in combat (And that when the list shrinks, all the animation triggers still go to the right place…). This is such a headache. I’ve taken a few steps to try and diagnose-- the “HurtEnemy2” bool, for instance, functions the same as “HurtEnemy1” despite having a different target in the script.
It’s probably better if I refactor everything so that the prefab itself has all the stats, isn’t it? … Sighhhhhhhhhhhhhhh. If there’s a way I don’t have to result to that, I’m all ears. Thanks in advance!
-Elaine