Referencing a non static member with an instantiated object - c#

I want this class to render a grid each time it is instantiated, but I am getting the error, error
CS0120: An object reference is required to access non-static member
`UnityEngine.GameObject.GetComponent(System.Type)'
So I instantiate an object of Renderer called Rend and set that equal to the non-static member but I am still getting the error? Any help would be greatly appreciated as I have researched for several hours and still can't figure this out.
using UnityEngine;
using System.Collections;
public class SetGrid : MonoBehaviour {
public int x = 1;
public int y = 1;
void Start()
{
Renderer Rend = GameObject.GetComponent<Renderer>().material.mainTextureScale = new Vector2 (x, y);
}
}

I am assuming this script is part of your grid game object which also has a component of type Renderer.
The correct syntax to scale the texture of the Renderer is following:
public class SetGrid : MonoBehaviour {
public int x = 1;
public int y = 1;
void Start()
{
// Get a reference to the Renderer component of the game object.
Renderer rend = GetComponent<Renderer>();
// Scale the texture.
rend.material.mainTextureScale = new Vector2 (x, y);
}
}
The error message was thrown because you tried to call GetComponent on a type of GameObject and not an instance of GameObject. The script itself is already in the context of a GameObject meaning that you can just access a component with GetComponent from a non-static method.

The problem is not with the Rend object, it's caused by the fact that the GetComponent method is non-static. That means you need to instantiate a GameObject object and use that one to call GetComponent.

Change GameObject.GetComponent to gameObject.GetComponent, so that you're referencing the gameObject that this MonoBehaviour script belongs to.
Or you can even not use gameObject.GetComponent and just use GetComponent by itself.
See the MonoBehaviour inherited members for details.

Related

Add variables to a transform script on a prefab, how-to?

So I am able to Instantiate new objects at runtime and they spawn in with the correct scripts attached however the scripts do now spawn in with the variables fixed in their slots.
I need a way to spawn prefabs with the scripts attached AND the variable slots in the script are all filled in.
Deploy capsule script (linked to main camera)
public class deployCapsule : MonoBehaviour
{
public GameObject CapsulePrefab;
public Path path;
public float respawnTime = 1.0f;
void Start()
{
StartCoroutine(capsuleWave());
}
private void spawnCap()
{
GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.transform.position = new Vector2(1.0f, 1.0f);
path.followers.Add(a);
Debug.Log("1");
}
IEnumerator capsuleWave()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
spawnCap();
}
}
}
Path Follower script
public class PathFollower : MonoBehaviour
{
public float movementSpeed;
//private float pathProgress = 0;
public GameObject objectToSpawn;
public Transform[] positionPoint;
[Range(0,1)]
public float value;
void Start()
{
Debug.Log(iTween.PathLength(positionPoint));
}
void Update()
{
movementSpeed = 10f;
if (value < 1)
{
value += Time.deltaTime / movementSpeed;
}
iTween.PutOnPath(objectToSpawn, positionPoint, value);
}
private void OnDrawGizmos()
{
iTween.DrawPath(positionPoint,Color.green);
}
}
I KNOW THIS IS NOT TECHNICALLY POSSIBLE.
But I need a method to get this done one way or another.
I am quite new to unity and would appreciate any help given.
Thank you in advance.
in deployCapsule, store a reference to the array of points
public Transform[] positionPoint;
assign the values in the inspector.
and then once you've instantiated the prefab, give it the array like this
//this is in the SpawnCap function
//GameObject a = Instantiate(CapsulePrefab) as GameObject;
a.GetComponent<PathFollower>().positionPoint = positionPoint;
//rest of your function
alternatively, set the values in the Awake() or Start() function of the newly instantiated Capsule by getting a reference to a class that has the data.
void Start()
{
positionPoint = GameObject.Find("Spawner").GetComponent<deployCapsule>().positionPoint;
}
After instantiating your capsule prefab and assigning a reference to it named a (I suggest you change this naming to something more logical)
GameObject a = Instantiate(CapsulePrefab);
Assuming your prefab already has the PathFollower component attached, you could use the GameObject.GetComponent<T> method to access it.
var pathFollowerComponent = a.GetComponent<PathFollower>();
After which, you could populate the positionPoint[] Transform's array (assuming that's what you're after) with references to the "Points" GameObjects located in the hierarchy and the scene.
It's up to you how to go about this:
You could create a tag on each point, use GameObject.FindGameObjectsWithTag("Point");
Obtain the children from the "PathFollower" GameObject and add its child transforms to your array
Create a singleton instance or a "GameManager" class which stores the points located in a scene
If you create new points dynamically, create a listener and invoke events to add the new points to the array whenever they're instantiated.
Note that the mentioned above may not return the points in the order you placed them, so you may need to sort them! In general, there are many other ways which you can find by searching the forums, or on Google!
The issue here is that your prefab is in project while the path nodes are in scene. You have two approaches to fix that.
First, your path nodes are under a parent object, that parent holds a container script:
public class PathNodes : MonoBehaviour
{
[SerializeField] private Transform m_nodes;
public Transform [] Nodes => m_nodes;
}
Either you use the singleton pattern (yes it is fine when used properly) or have the newly created object use FindObjectOfType then you can access the nodes.
The second solution is to have the prefab of your object to create in the scene as an inactive object. Being in the scene, you can then drag and drop all you need from the scene into it. The prefab is dragged in place of the original project prefab (CapsulePrefab) and when creating a clone of it, you just need to set it active.

How can I reference a game object on my scene in a prefab component I have just instantiated?

Currently I am learning both Unity and C#. I am working on a small game where I control a spaceship on the screen, while meteors are spawning in a random position outside of the camera's visible space, then start to move towards the ship.
For this I am trying to refer to the ship game object in a component on a meteor prefab, to get it's position and the angle needed to start moving towards the ship.
public class meteorPath : MonoBehaviour
{
public float speed = 10f;
public Rigidbody2D rb;
public GameObject ship;
void Start()
{
int typeOf = Random.Range(2, 11);
Vector3 posOf = new Vector3(Random.Range(-7f, 7f), Random.Range(16f, 8f), 0);
transform.localScale = new Vector3(typeOf, typeOf, 1);
transform.localPosition = posOf;
}
}
How can I make get the player's position to calculate the angle needed every time I instantiate a meteor?
I'm guessing that you're instantiating everything at runtime.
You would either do:
GameObject.Find(YOUR OBJECT NAME)
GameObject.FindGameObjectWithTag(sometag), only if your player has a tag
Make player's class singleton and reference it from other classes with PlayerClassName.InstanceName and reference the position.
If you're not instantiating everything but is a static scene, then just make a prefab of the meteor with the player's reference inside
one way to get references is to create instanced game manager:
and when meteor is created you have it get player position from that instanced GameManager.
in start of meteor:
private Vector3 playerPosition = GameManager.instance.playerPosition.transform.position;
in GameManager:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public static GameManager instance;
public GameObject playerPosition;
private void Awake()
{
instance = this;
}

rigidbody tab not showing in unity

For some reason, the tab in my unity script for rigid body isn't showing up, and nothing's working.
using UnityEngine;
public class PlayerMovement : MonoBehaviour {
public Rigidbody rb;
// Start is called before the first frame update
void Start ()
{
Rigidbody.AddForce(0, 200, 500);
}
// Update is called once per frame
void Update()
{
}
}
This is very confusing for me, any help?
Btw, I get this error:
"Assets/PlayerMovement.cs(12,9) error CS0120: An object refrence is required for the non-static field, method, or propererty 'Rigidbody.AddForce(float, float, float)'
You made a typo. Right now you are refering to Rigidbody insted of the variable name you defined called rb.
So you would need to write this instead:
rb.AddForce(0, 200, 500);
Try:
[SerializeField] public Rigidbody rb;
Since you put RigidBody, the class, it thinks you are trying to use a static method, which is not what you want to do. AddForce is not a static method, you need to call in on the instance of the RigidBody you created i.e. rb.

Change one attribute value of a script so it effects all gameObjects that this script is attached to

How do I change one or two attribute values of a script so that it effects all the gameObjects that this script is attached to?
For example making attributes SphereSmall and SphereBig global
public Vector3 SphereSmall = new Vector3 (0.001f, 0.001f, 0.001f);
public Vector3 SphereBig = new Vector3 (0.0015f, 0.0015f, 0.0015f);
Two gameObjects has this script attached to and I changed the attribute of public variables SphereSmall and SphereBig on one GameObject. I want this value to be changed in second GameObject as well.
I'm new to unity as well, but here are some solutions:
1) If you're talking about multiple instances of the same object, simply create a prefab out of that object and update the properties of the prefab.
https://docs.unity3d.com/Manual/CreatingPrefabs.html
2) If you're talking about instances of different objects, you can try using the multi-select functionality of the unity editor, this will let you edit all common properties. This is easy if you have lower number if instances and are grouped under a parent object in the Hierarchy pane.
3) If you're talking about instances of different objects and you don't mind seeing the effect of your updates only at run-time: you can try using the ScriptableObject class:
[CreateAssetMenu]
public class CommonObjectProperties : ScriptableObject
{
public Vector3 SphereSmall = new Vector3(1, 0.001f, 0.001f);
public Vector3 SphereBig = new Vector3(0.0015f, 0.0015f, 0.0015f);
}
After you create this script, go to Assets > Create > Common Object Properties:
Now you can use this ScriptableObject instance to add the common values to your objects and after you update them inside the ScriptableObject instance, they will update across all objects.
ObjectScript is the MonoBehaviour script to put on your objects:
public class ObjectScript : MonoBehaviour
{
public CommonObjectPropertis commonProps;
public Vector3 ObjectScriptSmallSphere;
private void Start()
{
ObjectScriptSmallSphere = commonProps.SphereSmall;
}
}
How it should look in the designer:
I'm sure there are plenty of other ways to do this, best of luck!
You could add [ExecuteInEditMode] to your script so it runs while the editor is running. From there you could check if the values are being changed and then update them. Something like this:
[ExecuteInEditMode]
public class MyScript : MonoBehaviour
{
public int myValue;
private int oldValue;
void Update ()
{
if (oldValue != myValue)
{
MyScript[] objects = FindObjectsOfType<MyScript>();
foreach(MyScript myObject in objects)
{
myObject.myValue = myValue
}
oldValue = myValue;
}
}
}
This isn't best practice though so I would recommend looking into using prefab variants instead.

Unity2D: UnassignedReferenceException: Variable has not been assigned instantiate

For some reason I get an error which looks like this:
UnassignedReferenceException: The variable LevelComplete of NPad1 has not been assigned.
and this is my code:
public class NPad1 : MonoBehaviour {
public Sprite img1 , img2;
public Rigidbody2D LevelComplete;
void Start () {
gameObject.GetComponent<SpriteRenderer> ().sprite = img1;
}
// Update is called once per frame
void OnTriggerEnter2D(Collider2D other) {
gameObject.GetComponent<SpriteRenderer> ().sprite = img2;
Instantiate (LevelComplete);
}
What have I done wrong?
Referring to this;
Clones the object original and returns the clone.
Which means you will have to instantiate LevelComplete before calling Instantiate(), which returns a clone of the existing object. You probably haven't set the instance in the Unity inspector. For more info, visit this guide on setting public variables.

Categories

Resources