CS0120 Cant set layer mask from different script - c#

I'm making a game where i want to change which objects my player can collide with by changing the layer mask, but every time I try to change the variable in a different script it throws this error
Error CS0120: An object reference is required to access non-static
member `RaycastController.jumpableCollisionMask'
The code for where i create the variable:
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (BoxCollider2D))]
public class RaycastController : MonoBehaviour {
public LayerMask collisionMask;
public LayerMask jumpableCollisionMask;
The code for where i set the variable
using UnityEngine;
using System.Collections;
public class PlayerChanger : MonoBehaviour {
public float numberOfPlayersPerLevel;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown (KeyCode.E)){
RaycastController.jumpableCollisionMask = 11;
}
}
}
I have tried using a setter but i couldn't get it to work. Thanks in advance and have a nice day =).

jumpableCollisionMask = 11
not
RaycastController.jumpableCollisionMask = 11
Note that you likely have another problem:
You set layer masks (which are just int) like this:
int layerMaskDogs = 1 << LayerMask.NameToLayer("Dogs");
int layerMaskFruits = 1 << LayerMask.NameToLayer("Fruits");
ok?
Never use "= 11" or any number or other value. In Unity it is now only possible to use the form 1<<LayerMask.NameToLayer("Blah")
Finally note you are using public to declare the LayerMask. That can be a bit confusing -- you only do that if you want to set it in the editor. If that's what you want to do, fine. But if you don't need to do that, just use private.
Finally note that you have this is TWO DIFFERENT SCRIPTS!!! This is the most basic problem in Unity. Fortunately it is easily solved:
-- add a public variable to your SECOND script
public class PlayerChanger : MonoBehaviour {
public RaycastController myRC;
-- IN THE INSPECTOR take your "RaycastController" and drag it to that public variable
-- Now use it like this
public class PlayerChanger : MonoBehaviour {
public RaycastController myRC;
...
...
...
//whenever you need to use it...
myRC.jumpableCollisionMask = 11;
Please read the literally 1000s of QA on this! Example, How to access a variable from another script in another gameobject through GetComponent?

Related

Scriptable Object is null when dragged to field inspector?

I'm a novice in programming / unity and trying to use scriptable objects, but having a hard time.
I'm trying to use SO as a way to store the base attribute data of players, monsters, etc.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu(fileName = "New StatData", menuName = "Scriptables/StatData", order = 0)]
public class StatData : ScriptableObject
{
[SerializeField] public float[] _stats;
public StatData()
{
_stats = new float[(int)StatType.Num];
}
}
The class is simple. Only has a float array(StatType is an enum).
So I made the SO in the project window under the Resources folder,
assigned all the values via the inspector,
and dragged it into the field in my StatContainer class, which deals with all attribute changes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public enum StatType
{
MaxHP,
MaxMP,
Strength,
Defense,
Magic,
Resistance,
MoveSpeed,
Num,
}
public class StatContainer : MonoBehaviour
{
[SerializeField] protected Stat[] _stats;
[SerializeField] protected StatData _statData;
void Awake()
{
Init();
}
void Init()
{
_stats = new Stat[(int)StatType.Num];
for(int i = 0; i < _stats.Length; i++)
{
_stats[i] = new Stat((StatType)i, 0);
_stats[i]._currentValue = _stats[i]._baseValue = _statData._stats[i];
}
_currHP = _stats[(int)StatType.MaxHP]._baseValue;
_currMP = _stats[(int)StatType.MaxMP]._baseValue;
}
}
I tried debugging, and in line 35 of the StatContainer class, the _statData itself is null.
I can see that it's referenced in the field in the inspector, but it's still null in debug.
I found out that if I use Resources.Load, no problem occurs.
But if I drag - drop the SO into the inspector, it's always null.
Is this not the way to use SO? or am I doing something wrong?
If I make an instance of the SO by ScriptableObject.CreateInstance,
it means that I have to assign all the values by script, and that's not what I want,
because I thought that the convenience of assigning the values in the inspector and drag-dropping or loading the SOs were a big part of using them.
It hasn't been long since I started programming and used unity, so I would much appreciate any enlightenment.
Thanks in advance!
I would answer this as a comment, but I don't have the reputation yet, as I am also pretty new. Could it be the that object you are referencing the script on is a prefab? Sometimes if you don't hit apply on the prefab, it just doesn't accept that you've referenced it in the Inspector field. That could possibly be the issue, but I have no experience with Scriptable Objects, so I could be absolutely wrong.

Unity communication between scripts

I'm making a Unity3D game. I want to implement a connection between the script Timer.cs and Collide.cs, by which they exchange the variable obji. And before you mark this question as a duplicate I want to mention that have already read this tutorial. As a result of the solution provided I get the error
A namespace cannot directly contain members such as fields or methods
Can you provide a solution for exchanging information between scripts that have no element in common. I want Timer.cs to get the variable obji from Collide.cs
Timer.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Timer : MonoBehaviour
{
public ScoresManager ScoresManager;
Text instruction;
// Start is called before the first frame update
void Start()
{
instruction = GetComponent<Text>();
InvokeRepeating("time", 0, 1);
}
void time() {
if (timeLeft <= 0){
/* if(move.obji() <= 0){
instruction.text = "You win!";
}else{
instruction.text = "You lost!";
}*/
} else {
timeLeft = timeLeft - 1;
instruction.text = (timeLeft).ToString();
}
}
// Update is called once per frame
int timeLeft = 30;
void Update()
{
}
}
Collide.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Collide : MonoBehaviour
{
public Text txt;
public int obji = -1; //this is an example, I always try to initialize my variables.
void Start()
{ //or Awake
obji = GameObject.FindGameObjectsWithTag("Enemy").Length;
}
void OnCollisionEnter(Collision collision)
{
if (collision.collider.gameObject.tag == "Enemy")
{
transform.localScale -= new Vector3(0.03F, 0.03F, 0.03F);
Destroy(collision.collider.gameObject);
obji = obji - 1;
Debug.Log(obji);
if ((obji) > 0)
{
txt.text = (obji).ToString();
}
else {
txt.text = "You win!";
}
}
}
}
Communication between scripts like this (sharing properties of one class with another class) is a very common task in Unity. The script that needs the value of a property of another class should get a reference to that other class.
In your example, since Timer needs to access the obji property from the Collide class, you need to add a reference to the Collide class to the Timer class:
public class Timer : MonoBehaviour
{
public Collide _collide;
// The rest of the script...
}
Then, in the Inspector in Unity, you need to drag a GameObject that has the Collide script attached to the _collide property of the GameObject with the Timer script attached.
Finally, you can access the obji property through your newly created reference:
if (_collide.obji > 0)
See this tutorial from Unity which covers this topic in depth.
The error you've once received:
A namespace cannot directly contain members such as fields or methods,
tells you that in a namespace cannot be placed any methods or fields (i.e. variables) directly. A namespace can only contain
classes,
interfaces,
enums,
delegates,
structs
namespaces.
Generally speaking, a namespace is used to provide certain scope and organize entities.
There are many ways you can get access to another class's member fields. The cleanest and simplest way is through a so-called Getter method (also through get properties). You should avoid using and referencing public fields. For example, in your Collide class
// You don't have to always initialize your fields: they have default values.
// Initialize only when you need to.
private int obji;
...
public int GetObji() {
return obji;
}
Now, to call that method you need a proper reference to it. For that you can simply add that as a parameter in your Timer class:
public Collide CollideRef;
...
// Get the field
CollideRef.GetObji();
And then just drag and drop the GameObject, having the Collide component onto it.

Operator `<=' cannot be applied to operands of type `VictoryCountdown' and `int'

using System.Collections;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class VictoryCountdown : MonoBehaviour
{
public float victoryCountdown = 300.0f;
public Text startText;
void Update()
{
victoryCountdown -= Time.deltaTime;
startText.text = "Survive until dawn!: " + (victoryCountdown).ToString("0");
}
}
/////////// 2nd Script below ///////////////////
using UnityEngine;
public class VictoryManager : MonoBehaviour
{
public VictoryCountdown victoryCountdown;
Animator anim;
void Awake()
{
anim = GetComponent<Animator>();
}
void Update()
{
if (victoryCountdown <= 0)
{
anim.SetTrigger("Victory");
}
}
}
Hello, I'm a beginning student so this may be an obvious error. I need to create a countdown timer to end a game. I believe that I have everything working, but ran into this issue at the final hour.
The first script creates a timer and then counts down to 0. The second script triggers the victory screen animation. Unity is returning the error:
Operator <=' cannot be applied to operands of typeVictoryCountdown'
and `int
I made some progress, but hit this hurdle and was hoping someone more experienced could tell me what I have done wrong.
You have a problematic naming convention. Also, you are trying to compare the
VictoryCountDown object with an int and that's not possible.
you can easily fix it like this. But it'll look like a mess...
if (victoryCountdown.victoryCountdown <= 0)
{
anim.SetTrigger("Victory");
}
It looks like you are defining an object of type VictoryCountdown, and you are naming that object victoryCountdown. Your comparison isn't accessing the class variable victoryCountdown, but the object. To get the variable, you have to do something like victoryCountdown.victoryCountdown, where you are accessing the variable through an instance of the class (though I would recommend changing the name of the class instance to avoid this confusion).
I would also note that the variable you want is a float and 0 is an int, so that comparison might not work as well (I'm not as familiar with how C# handles this kind of type disparity)

C#:Unity:Having trouble reference Rigidbody2d from different script

My scene has a main character, a balloon and a tether. I have a spring joint 2d connected to the balloon and I want to be able to change the connected body to the object the player clicks on. So far I have the following 2 scripts, one for the balloon and one for the connecting body:
Balloon:
using UnityEngine;
using System.Collections;
public class BalloonTethering : MonoBehaviour {
public SpringJoint2D theSpringJoint;
public Rigidbody2D theTether;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
theSpringJoint.connectedBody = theTether;
}
}
Connecting Body:
using UnityEngine;
using System.Collections;
public class TetherAny : MonoBehaviour {
public GameObject mainBalloon;
public Rigidbody2D iAmATether = new Rigidbody2D();
// Use this for initialization
void Start () {
mainBalloon.GetComponents<BalloonTethering>();
iAmATether = this.gameObject.GetComponents<Rigidbody2D>();
}
// Update is called once per frame
void Update () {
}
void OnMouseDown(){
BalloonTethering.theTether = iAmATether;
}
}
I keep getting the following two errors on the TetherAny script:
(12,17): error CS0029: Cannot implicitly convert type 'UnityEngine.Rigidbody2D[]' to 'UnityEngine.Rigidbody2D'
(21,34): error CS0120: An object reference is required to access non-static member 'BalloonTethering.theTether'
If anyone could tell me where I'm going wrong it would be much appreciated :)
Thank you!
From the first error line I can tell that GetComponents() will return multiple Rigidbody2D object, not only one.
http://docs.unity3d.com/ScriptReference/Component.GetComponents.html
http://msdn.microsoft.com/en-us/library/aa288453%28v=vs.71%29.aspx
Use these two links to understand what is actually happening.
On the second one.. You are trying to access a member of a class of which you don't have the object to (that's not how you access other objects members)
http://msdn.microsoft.com/en-us/library/x9afc042.aspx
It seems to me that you should learn how to program the basics first, honestly. But that's just my opinion.
(12,17): error CS0029: Cannot implicitly convert type 'UnityEngine.Rigidbody2D[]' to 'UnityEngine.Rigidbody2D'
GetComponents returns a LIST of Rigidbodies. You cannot assign an entire list to one object. You need to use GetComponent, not GetComponents. Singular. The '[]' after Rigidbody2D in the error denotes that it is a list, not a single object.
(21,34): error CS0120: An object reference is required to access non-static member 'BalloonTethering.theTether'
This is because you never tell it what BalloonTethering you want it to reference. You need to use GetComponent() on the balloon object. There are other problems here, I'm surprised you aren't getting more errors. As soon as you attempt to access any of these variables there will be problems! I'll fix up the first script to get you on your way
using UnityEngine;
using System.Collections;
public class BalloonTethering : MonoBehaviour {
public SpringJoint2D theSpringJoint;
public Rigidbody2D theTether;
// Use this for initialization
void Start () {
theSpringJoint = this.gameObject.GetComponent<SpringJoint2D>();
}
// Update is called once per frame
void Update () {
}
}
You'll need to assign an object to theTether if you want anything to happen when you make it the connectedBody

Unity C# Null Reference Exception

I am trying to get data from an int variable in Unity using C# code.
Below is the C# code I am using to get the int.
using UnityEngine;
using System.Collections;
public class endGameMessage : MonoBehaviour {
public static int score2;
void Start () {
GameObject thePlayer = GameObject.FindWithTag("Player");
gameScript game = thePlayer.GetComponent<gameScript>();
score2 = game.score;
}
// Update is called once per frame
void Update () {
Debug.Log (score2);
}
}
Below is the code from the other script I am trying to pull the data from.
using UnityEngine;
using System.Collections;
public class gameScript : MonoBehaviour {
//score
public int score = 0;
void OnTriggerEnter(Collider other) {
if(other.gameObject.tag =="hammer"){
GameObject.FindGameObjectWithTag("pickUpMessage").guiText.text = ("Picked Up A Hammer");
Destroy(other.gameObject);
Debug.Log("collision detected hammer");
audio.PlayOneShot(gotHit);
score = score+10;
}
}
}
I can get the the int value to come across to the other script but its always 0 even if the int was meant to be 10.
My question is how would i keep the value across the scripts? Any help is appreciated.
try this
public static int score2
{
get
{
return GameObject.FindWithTag("Player").GetComponent<gameScript>().score;
}
}
You have a lot of possibilities.
The first one is to set your Score as a static argument for you gameScript.
So you can access it anywhere just like that :
int myScore = gameScript.Score ;
And the declaration should be :
public static int score;
The second possibilities is far better if you want to save a lot of differents values from differents script.
In this case, you need to define a gameContext singleton.
If you don't know what is this, you should take a look at singleton in C# :
[https://msdn.microsoft.com/en-us/library/ff650316.aspx]
Singleton will allow you to have a single instance of your gameContext.
In your case, your singleton will have a Score attribute.
And you will be able to get the value from any scene and any scripts.
This is the best way so far.
score2 is read once at start and then never again. int is an integral type in C# and thus passed by value i.e. it receives a copy. There several ways to solve this problem.
The easiest solution is to access the gameScript.score directly - it provides read/write access to everyone anyway. To encapsulate it you may choose to define a property.
A better way could be to define a new class GameStatus which holds all relevant things. This can be implemented as singleton for example.

Categories