Add to list of class in c# (unity) - c#

I'd like to create a short static function which I could call from everywhere to add into a List of Transform (in Unity), here's what I got:
public class MultipableTargetCamera : MonoBehaviour
{
public List<Transform> targets;
public static void AddToCamera(Transform target)
{
targets.Add(target);
}
}
But I get an error message in Unity after saving my script "An object reference is required for the non-static field, method, or property 'MultipableTargetCamera.targets'".
I've tried many things and researched a lot but I can't find any solution that fits my needs.
I want to keep a List of Transform, I dont want use an array or to use a list of strings/ints.
Any ideas?

Your method is static while your field is not. To understand this, ask yourself: Imagine you initialize multiple of these objects, what is the right "targets" list?
Besides of the already commented fact that static can be considered bad practice in this case, the answer is:
You can not access a non-static class member in a static function of that class.

Related

CS0120 Attempting to invoke a method on a different script, but this error is produced

I'm very new to coding, so apologies if any terminology is wrong. The code is trying to change a bool from false to true (it will do something more significant later, but I'm having issues doing this which is much simpler). I'm doing this in unity if that changes anything.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class AnimalPositionalUpdates : MonoBehaviour
{
public PositionArrays ScripBeingAcessed;
// Use this for initialization
void Start()
{
//Find where the position is going to be input
int ArrayPosition = ScripBeingAcessed.FoodPosition.Length + 1;
PositionArrays.PositionBeingUpdated = transform.position;
}
// Update is called once per frame
void Update ()
{
}
}
Second Script (the one that I'm trying to influence)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PositionArrays : MonoBehaviour {
public bool PositionInProcess = false;
public Vector3 PositionBeingUpdated;
public Vector3[] FoodPosition = new Vector3[0];
// Use this for initialization
void Start () {
}
public void ArrayPosUpdate()
{
PositionInProcess = true;
}
// Update is called once per frame
void Update ()
{
}
}
Any help would be appreciated. As far as I know, there is some issue with me trying to use a static method like an instance??? Idk where it starts being static, and putting static in the method declaration for both only causes the same error to appear again referencing different components.
The error Is on line 16 of the first script.
Full error message
"CS0120 An object reference is required for the non-static field, method, or property 'PositionArrays.PositionBeingUpdated' 16 Active"
Obviously you are lacking fundamentals of OOP and delved into Unity development right away. You can do this, but I guess that programming in Unity will Taint your C# if you did not learn it properly. Having said that, you could certainly do it, but I'd suggest learning proper C# first and then use that sometimes uncommon Unity style.
There is some confusion around how the fields of your class are used, so let me explain: Usually, a class is a blueprint of sorts of which you can create instances. All of these instances adhere to that blueprint, which tells you exactly how you can use those instances (this is sometimes called implicit interface) and which data they contain (this is where Unity is somewhat sloppy). An instance bundles up the data with the methods you use to access and manipulate the data and you "always" need an instance to access these members, usually through a variable.
In your case, this variable is ScripBeingAcessed. This is the variable that holds your instance (at least if you did not forget to assign it) and therefor, you'd need the variable to access the field PositionBeingUpdated
void Start()
{
//Find where the position is going to be input
int ArrayPosition = ScripBeingAcessed.FoodPosition.Length + 1;
ScripBeingAcessed.PositionBeingUpdated = transform.position;
}
On static
Besides the members of a class that form the actual blueprint to create instances from, there are members that are accessed through the class itself. These are called static members. Anyway, since they are not bound to an instance, static members that contain any data will be the same regardless of where you access them from. This may be fine, if the static members are private (only instances of that class can access it) but I'd avoid it otherwise, since this creates a global state, which is not safe of being manipulated from other classes and can thus lead to hard to debug errors.

Examples of static's utility?

I navigated the site and found no topic that asked (or gave) specific examples of static's utility on C#. I am a beginner and wanted to find given cases in which the usefulness of statics are proved, in order to go further than the conceptual understanding of what a static class/method/etc is. I know only of one or two examples, such as being able to create a method that produces an object or a value when ran, but keep that one value "for ever", by the means of removing the new values created (when the script runs again) if a value has been created before. The code for that is this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MusicPlayerScript : MonoBehaviour {
static MusicPlayerScript instance = null;
// Use this for initialization
void Start () {
if (instance != null)
{
Destroy(gameObject);
print("Duplicate self-destructing");
} else
{
instance = this;
GameObject.DontDestroyOnLoad(gameObject);
}
}
// Update is called once per frame
void Update () {
}
}
What other examples could anybody give me? Thank you!
That's an easy one. If you have something to do that is not directly related to a specific object of the class you want to group it into, you define a static method. For example if you need a very specific helper function that acts on one of your properties but not on the whole object.
A static member variable allows you to define for example a singled-out object of your class. For example if your class is "Scene" and you want an all-encompassing Scene-object named World, you would define static Scene World.
In many ways statics can be considered what has been known as globals in older programming languages. What makes them less dangerous than globals is proper namespace resolution. You don't see them everywhere unless you know how to get to them, ie. on which namespace path.

Use a public attribute in a static method on c#

I created a plugin and I'm trying to use it on a class, the problem is that the method I'm trying to use in this class is a static method.
The struct of the plugin implementation is this:
The problem is in the method called TestMethod, on the TestClass class.
I can't use the attribute TestPlugin because it is not a static property.
I've tried to use it as static, but when I change this the TestPlugin property becomes null.
For this reason I tried to find a way to use it as a normal property, but after a lot of search I had not been able to find a way to do it.
The code is as follows:
TestPlugin declaration:
[ImportMany]
public IEnumerable<ITestPlugin> TestPlugin{ get; private set;}
Use of TestPlugin attribute:
private static void TestMethod(){
...
// Here Visual Studio says that :
//An object reference is required for the nonstatic field, method, or property 'ToastPlugin'
foreach(plugin in TestPlugin){
//Plugin's use
}
...
}
Edit:
Is there a way to use TestPlugin inside of TestMethod without declaring TestPlugin as static, for the reasons said before?
Is there a way to use TestPlugin inside of TestMethod without
declaring TestPlugin as static, for the reasons said before?
Quick answer is no.
Basically you have the following options:
Make TestPlugin static as well.
Make TestMethod not be static.
Make TestMethod take a reference to a TestClass object as a parameter.
Add a static collection of IList<IEnumerable<ITestPlugin>> and in the get/set methods of the TestPlugin add/remove the class from that new collection.
Which of those four you would choose depends upon exactly what you are trying to achieve.

How do I use variables in a separate script in Unity3D?

Title explains it all, I want to know how to access variables from another script. I've searched online, but found nothing that's worked.
You could make a class, instantiate an object of the class and access propterties.
Or you could use static variables.
Or even beter, lets say you have a GameManager.cs script attached to an empty object called GameManager. And you want to access its variables form the LevelManager.cs script. You do this inside the LevelManager.cs
public GameManager gameManager;
Then you can drag and drop your GameManager empty object to this public field, and everytime you want to access a variable you type gamemanager.yourVariableHere
Or, if you dont want to drag and drop:
in the start method...
void Start()
{
gameManager = GameObject.Find("GameManager");
//this way it finds your object automatically
}
Hope it helped, good luck.
First you need to make your variables public. Then get the GameObject, get the Componend and access your variable.
var variable = GameObject.Find("name").GetComponent<ScriptClass>().yourVariable;
To add to the previous answer, if your class is a pure c# class and doesnt inherit from monbehaviour then must create an instance of class. If you want global access to certain variables you should look into static variables or implement a singleton pattern

A design for sending objects to be added to the appropriate data structure

I have a class called DataStructures where I have a set of public static data structures that store objects. To add an object to a data structures is an involved process requiring a number of checks to be carried out, processes to be remembered and data to be rearranged. In another class called Foo, I need to add objects to the data structures.
I was thinking I can do this by making a method called ObjectFeed which would take an object and the object's label as parameters. The label would tell the method which of the data structures the object should be added to. I would also have a method called addObject which would take the object to append and the appropriate target data structure as parameters:
Public Class DataStructures
{
public static List<obj> object1Storage = new List<obj>();
public static List<obj> object2Storage = new List<obj>();
...
}
Public Class Foo
{
public void ObjectFeed(/* PARAMETERS */)
{
//Code that generates an object called inspectionObject
//inspection object has an associated enum Type
if(objectType == Type.Type1)
{
addObject(inspectionObject, DataStructures.object1Storage);
}
if(objectType == Type.Type2)
{
addObject(inspectionObject, DataStructures.object2Storage);
}
...
}
private void addObject(obj inspectionObject, List<obj> objStorage)
{
objStorage.Add(inspectionObject);
//And a lot more code
}
}
Passing a public data structure as a parameter to a method that can just as well access that data structure directly doesn't feel correct. Is there a more clever and less intuitive way of doing this?
Edit:
In the example I originally contrived, the ObjectFeed method served no apparent purpose. I rewrote the method to look more like a method from the real world.
Where is the object type coming from? Passing a string value as a type of something is very rarely a good idea. Consider different options:
Create an enum for these values and use this. You can always parse it from string or print it to string if you need to.
Maybe it makes sense to have a couple of specific methods: FeedObjectType1(object obj), etc.? How often will these change?
Its really difficult to give you a definite answer without seeing the rest of the code.
Exposing public static lists from your DataStructures class is in most cases not a good design. To start with I would consider making them private and providing some methods to access the actual functionality that is needed. I would consider wrapping the lists with the addObject method, so that you don't have to pass the list as an argument. But again I am not sure if it makes sense in your case.
You seem to use DataStructures like some kind of global storage. I don't know what you store in there so I'm going to assume you have good reasons for this global storage.
If so, I would replace each list with a new kind of object, which deals with additions of data and does the checks relevant for it.
Something like:
interface IObjectStorage
{
void Add(object obj);
void Remove(object obj);
}
Each object storage type would derive from this and provide their own logic. Or it could derive from Collection<T> or something similar if collection-semantics makes sense. As your example is right now, I can't see the use for ObjectFeed, it serves as a fancy property accessor.
Selecting which property to access through a string sounds iffy to me. It is very prone to typos; I would rather use Type-objects available from any object in C# through the GetType-method or typeof() construct.
However. The whole setup feels a bit wrong to me, DataStructures et al.
First, testing your static class will be hard. I would pass around these stores to the types that need them instead. Replacing them with other stuff will also be hard, using interfaces will at least not tie you to a concrete implementation, but what if you want to use another location to store the objects in other code? Your static class is no longer relevant and you'll need to change a lot of code.
Maybe these things are out of your control, I don't know, the example code is a bit vague in that sense.
As pointed out in other answers:
The public static Lists are bad practice
Since the addObject method is the same for every data structure, it should be implemented as a data structure accessor.
To this end, I moved the instantiation of the data structures into Foo and moved the addObject method from Foo to a new class called StorageLibrary that more accurately represents the data structure architecture.
private class StorageLibrary
{
private List<obj> storedObjects = new List<obj>();
public void addObject(obj inspectionObject)
{
storedObjects.Add(inspectionObject);
//And a lot more code
}
}
public class Foo : StorageLibrary
{
//Declaration of libraries
public static StorageLibrary storage1 = new StorageLibrary();
public static StorageLibrary storage2 = new StorageLibrary();
...
private void ObjectFeed(/* PARAMATERS */)
{
//generate objects
if (objectType == Type.Type1)
{
storage1.addObject(inspectionObject);
}
if (objectType == Type.Type2)
{
storage2.addObject(inspectionObject);
}
...
}
}

Categories

Resources