I want to create a “random weapon generation system” similiar to Diablo. E.g.: Whenever a weapon is generated, the stats and effects of that weapon are “randomly pulled” from a set of effects.
To give you an idea, some effects could be:
Always on effects (these effects are always activated and dont require an activation trigger):
Increase stat1
Increase stat2 (e.g. increased chance for critical hit)
…
On Hit: Buff effects (activated contingent hitting a target):
Buff stat1, when weapon Hit target
…
On Hit: Spawn effects (activated contingent hitting a target):
Spawn effect1, when weapon Hit target
…
You get the idea
I want each weapon to draw a random number of effects and allow multiple effects of the same category (e.g. a weapon could have multiple OnHitBuff effects). Now there is my problem: I don’t know how to achieve that efficiently. I read the basics on interfaces, inheritance and composition over inheritance but still lack the fundamental starting point to get going.
This is basically what I have:
I define interfaces for each category of effect.
public interface IBuffOnHit
{
void BuffOnHit(Weapon weaponToBuff);
}
public interface ISpawnOnHit
{
void SpawnOnHit();
}
I define concrete classes for each effect.
using UnityEngine;
public class BuffStat1OnHit : MonoBehaviour, IBuffOnHit
{
public int buffAmount;
public void BuffOnHit(Weapon weaponToBuff)
{
weaponToBuff.stat1 += buffAmount;
}
}
using UnityEngine;
public class SpawnMinion1OnHit : MonoBehaviour, ISpawnOnHit{
public GameObject minion1Prefab;
public void SpawnOnHit( )
{
Instantiate(minion1Prefab, transform.position, Quaternion.identity);
}
}
In the weapons class I have some arrays for each effect to call the functions of the specific effect classes;
using System.Collections.Generic;
using UnityEngine;
public class Weapon : MonoBehaviour {
public int stat1;
public List<IBuffOnHit> buffOnHitEffects = new List<IBuffOnHit>();
public List<ISpawnOnHit> spawnOnHitEffects = new List<ISpawnOnHit>();
public void TargetWasHit()
{
ApplyBuffOnHitEffects();
ApplySpawnOnHitEffects();
}
public void ApplyBuffOnHitEffects()
{
for(int i = 0; i < buffOnHitEffects.Count; i++)
{
buffOnHitEffects[i].BuffOnHit(this);
}
}
public void ApplySpawnOnHitEffects()
{
for (int i = 0; i < spawnOnHitEffects.Count; i++)
{
spawnOnHitEffects[i].SpawnOnHit();
}
}
}
While this might work to fire the specific effects I have some questions which I hope you guys can help me with
How do I add the effects to the weapon in a random fashion? I was thinking of some kind of superclass for all the effects and let the weapon randomily draw the respective effects and add them to their list of effects (e.g. buffOnHitEffects) - but I dont know if thats possible.
How can I specifiy the gameObject that “SpawnMinion1OnHit” Spawns? This basically relates to question 1. If I could have some kind of mono superclass, I could simply define the “toSpawn” in the inspector.
I’ll start with an aside: If you’re doing the thing where you generate a name for it (“The Great Blue Sword of Stabbiness”, whatever), you should watch this video to keep from making item names that just sound weird in English. Also the rest of Tom Scott’s channel because he’s my favorite Youtuber but… I digress.
So back to the system. You seem to be on a good track. I would say, in addition to your interfaces, you should definitely have a base WeaponEffect class to inherit from, which can contain functionality common to all of your effects. Even if you don’t have any such functionality now, it’s tough to imagine a scenario where you won’t have it eventually.
#1. You can get a list of those effects using this code if they’re derived from the same class. From there, it’s just picking one type from the list and using AddComponent.
#2. This is probably a good time for Resources.Load, and your minion prefab would be in the Resources folder.
Hey StarManta, nice to “see” you again. You answered one of my noob questions roughly 1 year ago
That video will become handy…especially for non native english speakers like me
To #1: I must admit that I dont know how to get that working. Assuming that I added the class
using UnityEngine
public class WeaponEffects : MonoBehaviour{}
and changed the concrete effects to inherit from that class:
public class BuffStat1OnHit : WeaponEffects, IBuffOnHit
{
public int buffAmount;
public void BuffOnHit(Weapon weaponToBuff)
{
weaponToBuff.stat1 += buffAmount;
}
}
public class SpawnMinion1OnHit : WeaponEffects, ISpawnOnHit{
public void SpawnOnHit( )
{
Instantiate(Ressources.Load("Minion1", typeof(GameObject), transform.position, Quaternion.identity);
}
}
What would be the next step to put all classes that inherit from WeaponEffects into one list? And how would I access them? From what I understood,
var listOfBs = (from domainAssembly in AppDomain.CurrentDomain.GetAssemblies()
from assemblyType in domainAssembly.GetTypes()
where typeof(WeaponEffects).IsAssignableFrom(assemblyType)
select assemblyType).ToArray();
yields a list of System.Type[ ] which Iam not quite sure how to access.
Indeed, using a Type instead of hard-coded types can be tricky, but in this case it should be fairly straightforward, because the functions where you’re likely to need this, already can accept a Type as a parameter.
for (int i=0;i<listOfBs.Length;i++) {
if (thisIsTheTypeYouWant) {
theWeaponGameObject.AddComponent( listOfBs[i] );
}
// which is equivalent to: theWeaponGameObject.AddComponent( typeof(SpawnMinion1OnHit));
}
Thanks! I really appreciate your help! I got it running.
But I have one more question regarding performance, since I never used Resources.Load and program for mobile:
Since I cannot directly link prefabs in the inspector using that approach, I have to use Resources.Load which seems to be quite performance heavy for frequent operations like hit effects etc.;
From your experience, is Resources.Load way worse than direct instantiating in terms of performance if you cache the prefabs once a new weapon is created?
I mean something like this:
public class SpawnMinion1OnHit : WeaponEffects, ISpawnOnHit{
GameObject minion1Prefab;
void Start()
{
GetMinionReference();
}
void GetMinionReference()
{
minion1Prefab = Resources.Load("Minion1") as GameObject;
}
public void SpawnOnHit( )
{
Instantiate(minion1Prefab, transform.position, Quaternion.identity);
}
}
EDIT: Ah dang, I forgot: If I assign the weapon effects via System.Types[ ], I can’t assign specific draw probabilities to each effect, right? (Each weapon stat could have a different probability of being added on an object)
Caching the result of Resources.Load is a good idea, but it shouldn’t be all that performance-intensive, I wouldn’t think. What makes you say it is? Have you profiled it to find out where it’s spending its time?
Hm… that’s a very good question. I don’t know how you would go about setting different probabilities there - at least not without some pretty ugly workarounds. You could maybe make a Dictionary<System.Type, float> that returns probabilities, but filling out the values of that dictionary would be a trick in itself. If I think of a good solution to this I’ll come back.
While the weapon creation works fine, Iam currently facing some problems saving / loading weapons that have been created.
Here is how weapons are handled:
Each weapon consists of a basic prefab which gets instantiated as the weapon instance. Upon creation, each weapon receives a random number of effects which get added to that weapon. Those effects are stored as components which I add via System.Type and each stored component randomly rolls some stats upon creation.
How I wanted to tackle this problem:
Each weapon instance gets all components of type “Weapon Effects” and saves a “value” for each effect (this could be the rolled stats)
Upon saving, I put all the references into a binary formatter. But from what I read so far, unity doesnt support polymorphism for serialization. So I think that upon loading the specific Weapon Effects (i.e. SpawnMinion1OnHit), I cannot get a reference to add a specific component that inherits from Weapon Effects.
Any suggestions? It would be a great help If I just knew how to save all the components that inherit from “Weapon Effects” on a specific gameObject.
Edit: I know that I could get the indexes of the weaponEffects of listOfBs but that would probably cause trouble if I decide to add further classes that inherit from weaponEffects (since probably listOfBs changes when new stuff is added)