Reputation: 189
My unity project is growing and I'm a little intimidated.
I've created a Player that has a ton of scripts that are working together. (It will be even bigger lately tho.) This is how it looks like.
All the scripts that the player is compound of inherits from a basic script that just contain some protected static variables that can be changed from all the other scripts, so I can check any state of the Player from any single script.
Some of those:
public class BasicCharacter : MonoBehaviour
{
protected static Rigidbody2D rb2d;
protected static CharacterRenderer characterRenderer;
protected static Vector2 directionLookingAt;
protected static Vector2 movement;
protected static Vector2 attackPos;
protected static bool hasDashedAttack = false;
protected static bool hasFinalizerAttack = false;
protected static bool isUsingMovementSkills = false;
protected static bool isStringingAttacks = false;
...
This is an example of how I call some of that variables as condition to execute some other actions:
private GameObject GetAttackAnimation()
{
if(hasFinalizerAttack)
{
return empoweredAttackVFX;
}
else if (hasDashedAttack)
{
return dashedAttackVFX;
}
else if (isAttackCharged)
{
return chargedAttackVFX;
}
return basicAttackVFX;
}
My concern is that I don't feel I'm doing a clean and nice work here. I think it is a better way of facing this. In my code, I have to remember every single possible state the Player can be before introducing a new game mechanic.
I have a few questions:
Do I need a PlayerManager that keeps track of the possible behaviors?
Is there a way of not adding every single script to the game object so it could look cleaner?
Is the BasicCharacter script sustainable?
Upvotes: 1
Views: 153
Reputation: 516
Certain parts of your character can be made a bit more modular by using ScriptableObjects (https://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/scriptable-objects), they don't necessarily lower the amount of complexity (games are complex, you have to kind of accept that) but they can help at least de-clutter your player controller and spread your functionality across different more self-contained classes, which are conveniently built into Unity's editors allowing you to drag and drop them, and more importantly, edit them seperately from your primary player prefab, allowing you to avoid the 'huge wall of script data' issue.
In this case for instance, I would seperate ability data and buff/malus data into ScriptableObjects. You can set up whatever hierarchy of classes you want there, and modify them as seperate game assets to your core player (if you put enough work in you can even make them modular enough to work for enemies as well as your player, which is pretty handy!)
Once you have your scriptableobjects set up, you can give them some kind of base functionality like 'OnTick', 'OnTakeDamage' 'OnActivate' etc etc, even have some internal state like 'IsSkillActive' etc, then you simply store them as lists or dictionaries on your player object, and iterate through them. A quick pseudocode could be:
bool canInput = true;
foreach(Ability in Abilities)
{
if (Ability.IsSkillActive())
{
canInput = false; //still in the middle of an active ability
break;
}
}
if (canInput)
{
//Do allow player to have input here.
}
Or you could have:
class DamageOverTimeDebuff : ScriptableObject
{
int damagePerTick = 1;
OnTick(PlayerObject afflictedPlayer)
{
afflictedPlayer.TakeDamage(1);
}
}
In this way you can make abilities and effects a bit more modular, and build your player by composition, rather than having if statements for every single scenario.
That said, there's a tradeoff, this increases your level of abstraction, which makes extremely specific behaviour or special edge cases a bit harder to pull off. You may also spend a lot of time writing specific functions for your debuffs or abilities that only get used for one effect, in that case its just extra work.
This is just one possible strategy, the problem you're describing is one every game has to face and deal with in different ways. Maybe ScriptableObjects can help you pull apart your functionality into something more bite-sized, maybe they will just be extra boilerplate that gets in your way. It comes down to the specific needs of your game.
Upvotes: 3