my apology, it’s the same thing as above. it’s calling them for 6 different ones, so 60 errors. the actual ArmorCore# didn’t matter.
This is peculiar, it’s possible something in Unity’s deserialization process broke for this class during the changes?
Generic advice but try restarting Unity, removing the components from the prefabs and readding them again, or renaming the variable names?
I’m not following all the rationalizations but there is another thread in Scripting that discusses (a bit) what has happened here. What is with all the individual rank, armor, dodge and related stuff? Can’t some small utility class hold onto Rank properties/methods or “Level” ones (I can’t figure out what groups make sense but I know I couldn’t remember totalCritAvoid and totalArmor wouldn’t be easy for me to remember.
Armor.Total would and if I typed Armor I would be reminded of all the Armor-related stuff available.
that’s digging into a different discussion, but there are three things increasing the ‘power’ of the armor, two of which, level and rank, are the only numbers that need to go server side. level is restricted by rank, each rank and level increasing things by a certain amount, dependent on the specific armor type equipped, and a check to determine quality, quality increasing the amount levels have provided.
specifically from armor, those numbers are snagged by the ship and used when something impacts it. for the weaponry, a number of stats are going to be inserted from the ship into the totals of each of those, so they can apply that total to the bullets.
the whole thing isn’t for anyone else to necessarily figure out though, it’s about why im getting errors for something that shouldn’t really be happening as far as i can tell, and apparently as far as drgrandayy can tell either, lol.
Sorry didn’t mean to change the subject. I saw it as “a bit” related to complexity getting in the way of your engineering a working solution. In any case, carry on…
Im trying to understand your problem…
You have a class that holds data that all things use. The other things use this and put in their infoto store it(this sounds like scriptable objects).
So now you also have a class to hold all the stuff you need, and another class trying to use that information? Is that what’s going on?
And the parent class has a method/function that is trying to use information from the other class object but cant? Or rather you are trying to perform the calculations on the child class and just get the information on the main class?
I don’t think you will have to copy/paste anything 500 times(also inheritance would mean the child inherits from the parent so the child would have the functions, not the parent. and doing it the other way wont work i believe.) Its difficult for me to pinpoint what you want to achieve but I can start by saying look into Scriptable objects. They deal with a lot of what you’re talking about and probably have come across a similar enough issue for you to work off. And… i feel like at some point you’ll have to pass the object itself to the parent, this should give you the ability to go GamObject.getComponent(blah). or something along those lines(i still don’t have a firm understanding, sorry). Or otherwise pass the object in which you should be able to reference the object and .whatever() to call a method on it that returns a value. Your parent script would have to call it under a declare type(int string whatever) to take in the returned value and work from there. And my last guess would be to consider either Getters(&setters>.>) or Interfaces(add an interface to the child that assures that it will have the method you want which allows you to implement the code to find and run the method/function. So not using inheritance but using interfaces.
Again I am not sure what problem you’re having so I hope my guessing did something, glhf.
xD my problem is error that at lest two people now dont see why they exist.
the entire concept is simple. base class. it has methods that use fields/properties. to make those methods in the base class, those fields/properties have to exist in the base class, so they are “empty.” the child classes are attached to the objects that will be used. those child classes are essentially the base class, except they each have their own field/method values.
because of inheritance the child classes use the parent class methods on their own values. later, the child classes are going to get unique overriding methods to be used for other things, very specifically in combat stages.
again, this WORKS. it just tells me there are errors about things being serialized multiple times. and the errors don’t impact anything, a build happens, i can run it on my phone, it does all the things its supposed to. i was wondering what was being typed wrong, or what, to make those errors show up, whether its the inheritance style that’s broken, or unity.
and now i have a bunch of people trying to convince me that more complex solutions are what should be done, as far as i can see, than actually getting down to the core of the issue, which is ‘why would it be telling me these are being serialized multiple times.’ i think my answer is unity has a weird screw up in it somewhere, since everything works perfectly.
I get a sense that we aren’t going to be able to explain things to your satisfaction. If a funny smell comes from your car engine and it makes a weird noise BUT “it still works” it isn’t working by the definition typically used.
I’ve coded for 4 decades and there must be 100 years of experience in this thread and I will suggest (but I’m not trying to push you into believing it) that something amiss at the fundamental level. I am saying if the code you’ve posted (and I am one of those that can’t follow the purpose) is giving the compiler grief then you owe it to yourself to “reconsider” the approach.
Lot of people’s ideas and proposed solutions begin with “it would be nice if…” yet that isn’t how things work currently. It could be Unity, it could be C#, it could be you are using a wrench to hammer in a nail
And importantly not a single person has suggested a “more complex solution”. If it was more complex, took longer to run or was more likely to break I would bet money responsible coders here would be pointing those things out.
If nothing else try to keep in mind that we all write code here. If your solution was “cool” (by whatever measure you care to use) at least some of us would be jumping on it. We aren’t ragging on what you posted we’re offering insights on why despite it “working” that it might not be the ideal solution in the short to medium term and it looks like trouble in the long run.
Sorry for the length of the reply but consider reading past the “words” in all these replies and ask “why don’t they see how much sense this code makes”? Maybe explain what we are missing by not setting things up the way you have…
We’re confused
the first answer is, there’s not usually just one way to do something.
the second is, inheritance should literally be one of the answers to this, it IS intended to make child classes that have differences though they are the same object, else that wouldn’t exist at all.
i’m not trying to be argumentative here, but i’m trying to get to the root of a problem that’s just plain dumb, and that would be errors that pop up for no good reason, as someone has already said. is there more i need to show here? i mean, all of the problem issues are on display, and it seems to be some odd serialization thing that’s not an actual impediment, just thinks something that probably isn’t true. i’m quite the minimalist, and don’t see the need to make what… 1, then 18, 18x18… like 324 scripts to plug in to 6 objects, because you all seem to wholly believe that i should make a core, and then make different children and attach them to the object to get the rest, when i could have a core that handles all the basic stuff through the children, and then the children with their own 18 individualized variants of certain other methods (from the core, which is the actual way it’s usually used).
i’m just not seeing how that is the better answer than ‘why is my editor telling me that it’s serializing those things twice?’
i understand there is a lot of experience in here, and i fully appreciate it, i really do, but the answers in here seem like calling a tactical nuclear strike from orbit to kill a spider.
before i call that strike, i’d really like to understand if this is an actual editor only failure that (so far in testing) doesn’t actually affect anything but reading my log, or if there is actual damage in declaring fields/properties in this way.
by the by, tried the close it and open it, and that didn’t work lol. time to try readonly or nonserialize field, i guess.
I mean you posted this as the error:
Is this the full error? It looks like its missing half or part of the member’s name.
The same field name is serialized multiple times in the class or its parent class. This is not supported: Base(ArmorType3) < levelCritReduction >k__BackingField
yes, that is precisely copy/pasted. again, the number of the armor type doesn’t matter, the part in the <> are those 10 properties. 6 armor types, 10 of that error each, with those simple numeral/property name changes.
edit: wait a sec, it doesn’t like the <> things.
Then I guess Unity is soft-serializing the invisible backing member during domain reloads, causing this error as there is a backing memory for both the base and derived types.
You will need to do something like this, either on the derived or base type declaration:
[field: System.NonSerialized]
protected override float levelCritReduction { get; set; } = 0.05f;
To prevent Unity trying to serialize this member during domain reloads.
But seriously, this kind of code is not going to scale. Use a scriptable object for this data. Do calculations based on the data separately.
well that sounds ominous, define ‘won’t scale’?
Well I already mentioned that for every change to a value, you will need to recompile. You also can’t change these values at runtime. Imaging being at the stage to lots of testing and tweaking… Change value, recompile, enter play mode (another recompile), get to point to test value, test value. If the value isn’t right, exit play mode, change value, repeat process.
Can you see how long this will start to take?
For a scriptable object its just: change value whenever you please, including during play mode.
Whenever you want a new armour class, you need to implement a new type, and then override all these members. This takes time, and adds more code to your code base.
For a scriptable object, you just make a new instance, enter the values, and reference it wherever you need it. Substantially quicker, and doesn’t require any more code. You can even do this during play mode…
And as mentioned inheritance should not be used for purely data. There’s just no reason to do it. You only need the one type. Its an anti-pattern that will bog down your project.
And changing this to use scriptable objects isn’t going to be much of a change either. Just shift all the values into a scriptable object definition, make your instances and enter your data, then reference this scriptable object wherever you need it. Job done.
it’s not purely for data, again, it’s for having a core script that handles all of the use cases of armor for menus, etc, and for the differences in combat by having everything in existence going through the one type, because it filters into the variety of types. it just so happens that the values of each are different, and i was figuring this would be the easiest way, seeing as the mathematics are already done for those values to reach the desired numbers as one progresses.
i suppose i could write a 10k+ line script for armor core and try to get everything to if or case off of a numeral in combat, but that also seems like a horrible idea, when what i’m doing is physically working, just with that one type of weird error lol.
but i guess i’ll go back to the drawing board, because… everyone says this doesn’t work/won’t work?
you have to understand this is truly mystifying to me, this seems to be the essence of inheritance: having a base that you can call with one reference, and it will act on any child, so that you can form everything on the base, and have the child use different versions.
it’s like making a card game, define what a card is, then have individual cards derive from what a card is, and tell them to act differently as they need to x.x
Again it is going to prove valuable if you don’t write “10k+ line script” and other descriptions whose sole purpose is to make the unreasonable sound reasonable. It doesn’t cost $20 million dollars, there won’t be 500 more classes, etc., etc. Not a single person here has written a 10k script to make something easier to process.
Something really, really is up when you describe the purpose of inheritance. We do know what it is. I have to think you are redefining the basic rules of OOP.
Maybe (if you are willing) you can create a simplistic example with perhaps 2 or 3 properties that illustrate what you are trying to do. I get the nagging feeling it is the opposite of inheritance and you’re hoping you can bend the way it works into a shape you’re happy with.
I have classes that inherit classes that inherit classes to add functionality and have never been pained to make it work. The opposite is what I notice, elegance in how I can construct subclasses with unique behaviors with little effort and an almost guarantee that it will all work.
This is essential OOP (as you’ve written) so that alone should tell us you have screwed something up along the way.
I’ll give you a simple example:
// ArmorCore
protected virtual float rankArmorAmount { get; set; }//= 1f; //rank 20 = 20%
// ArmorType1
protected override float rankArmorAmount { get; set; } = 1f; //rank 20 = 20%
What are you gaining from this property being virtual and then overriding it?
the above was an exercise in getting rid of said errors.
as to lines of code, figure the methods are going to average about 8 to 12 per effect, up to 18 effects, over 6 armors, that’s 1280ish right there, and plus all the menu effects, reliant on the stats and effects from the armor, maths, etc, 10k may have been hyperbole, but still very significant. or, splitting all that up amongst multiple smaller scripts that will still need to be written and attached, x number of lines to attach those…
i’m not trying to be a doomsayer, i’m just highly skeptical of the necessity of splitting things up.
here’s a prime example of what is done.
ArmorCore is used in menu to fill out the information in the buttons (visual), by having the proper child armor attached to the button prefab. when you click, it fills a panel with the actual numbers associated with that child. simple enough, you click an upgrade button if you’re allowed, it upgrades, saves the new level, reloads the info on the panel, blah blah, normal refresh stuff.
same ArmorCore also transfers the information of the children to the ship (remember, they’re all different statwise in some way), allowing it to get it’s total stats from armor. in combat, any collision with bullet will filter to the core in an impacted method, which will be dealt with via ArmorCore, except using the overriding childs method (depending on bullet impact, enemy impact, timed effects, wall impact, [possibly instant destruction impact saving you once, still considering that for one of the armors]) things like that.
it’s a fairly simple thing, get all of the stats and do the math (in the children) and use them, in combat, all impacts just have to use the base ArmorCore to get to the child effects. and all of the math is controlled by two changing values, level and rank, that are saved and read back as needed.
And there’s no reason the data needs to be in the same type as the type that does calculations based on it. C# by definition is a Object Oriented Programming language. We create objects to encapsulate our needs. And when we want differing behaviour that works on the same data structure, it’s well understood that this responsibility should be split up, ergo, into multiple objects.
To be clear the code behind what I’m suggesting isn’t that complicated:
public class ArmoredCoreStats : ScriptableObject
{
[SerializeField]
private List<int> _hpPerRank = new();
public IReadOnlyList<int> HpPerRank => _hpPerRank; // collection shouldn't be modifiable to outside users
}
// plain C# object for the mutable runtime save data
[System.Serializable]
public class ArmoredCoreInstanceData
{
[SerializeField]
private int _currentRank;
public int CurrentRank
{
get => _currentRank;
set => _currentRank = value;
}
}
public class ArmorCore : MonoBehaviour
{
[SerializeField]
private ArmoredCoreInstanceData _instanceData = new();
[SerializeField]
private ArmoredCoreStats _stats;
public virtual int GetHpForRank()
{
return _stats.HpPerRank[_instanceData.CurrentRank];
}
}
Then you can make derived types of ArmorCore
if you want varying behaviour while the data structure remains the same.
We’re not saying to do this! You can still have derived types with different behaviour, but act on the same set of data in a different type. I’m not sure why you keep coming to this awful conclusion.
It will work but as mentioned it will start to bog your project down. Our advice is based on experience and well understood, tried-and-true principles. Data-driven design can really speed things up in the long term.
The point of inheritance is to enable polymorphism. Ergo, substitution. It’s so you can substitute a base type or interface with any of its derived types or concrete implementations, without having to care about the specific implementation of the derived type.
This doesn’t preclude breaking up your responsibility into multiple objects.
Like I said earlier, to have derived armour types with different behaviour is a correct use of inheritance. But there’s absolutely no reason for the data to also follow this same pattern. If the structure and/or its underlying implementation doesn’t change, it should be a separate object.
Yes, that in essence is correct. But when you have two cards that both do damage, you don’t need two different derived types to do different damage. You only need two different instances of the same type, with different values.
I just stopped by and haven’t the time to address every post here. However I want to clear up some general misconceptions.
First of all field initializers can only be applied to fields when they are declared. So when you declare fields in a base class, field initializers can only be used in the base class. You can not somehow initialize the fields multiple times through field initializers. A derived class can set / overwrite the initial values in the constructor, that’s the only way to actually change fields declared in the base class.
Properties are a completely separate topic.
Properties are just fancy methods that look like fields. The main issue with the suggested property solution is, that it used auto-properties two times. As a result each of the auto-properties will create their own invisible backing field. There’s no reason for that.
One solution when using properties would be to declare either an abstract property, so only the abstract methods of the property are created in the base class, so they can be properly overwritten in a derived class. However that means the actual fields would be declared only in the derived class but can be accessed through the property from the base class. However when you declare the properties as abstract, the class itself has to be abstract as well. Though in such cases that’s usually not an issue.
public abstract class Base
{
protected abstract int[] SomeProperty { get; set; }
}
public class Derived : Base
{
protected override int[] SomeProperty { get; set; } = {1,2,3,4,5};
}
If for some reason you can not / don’t want to use an abstract base class with the property approach, you can declare them just as virtual with dummy methods:
public class Base
{
protected virtual int[] SomeProperty { get { return null; } set { } }
}
public class Derived : Base
{
protected override int[] SomeProperty { get; set; } = {1,2,3,4,5};
}
Here again, the actual backingfields will be declared in the Derived class.
The other solution would be to change / initialize fields declared in the base class in the constructor of the derived class
public class Base
{
protected int[] SomeValues;
}
public class Derived : Base
{
public Derived()
{
SomeValues = new int[]{1,2,3,4,5};
}
}
Though as others have pointed out, this is in general a bad design and somewhat outdated way to use classes.
ps:
Just in case some people don’t understand what this line does:
protected override int[] SomeProperty { get; set; } = {1,2,3,4,5};
it actually breaks down to
private int[] m_SomeHorribleMangledName = int[]{1,2,3,4,5};
protected override int[] SomeProperty
{
get {
return m_SomeHorribleMangledName
}
set {
m_SomeHorribleMangledName = value;
}
}