boolean from another script in Unity3D - c#

So I've got two scripts, one is called EndCollider.cs it's somewhere on the map,
It have one OnTriggerEnter function which set a boolean to true.
using UnityEngine;
using System.Collections;
public class EndCollider : MonoBehaviour {
public bool isShow = false;
void OnTriggerEnter ()
{
isShow = true;
}
}
the other script is SlowDownRun.cs, it's on a monster object, in this script I'm trying to detect if the boolean from another script is true or not, if it is then move the monster.
using UnityEngine;
using System.Collections;
public class SlowDownRun : MonoBehaviour {
GameObject TrollScript;
EndCollider MonsterShow;
// Use this for initialization
void Start ()
{
TrollScript = GameObject.Find("Troll");
MonsterShow = TrollScript.GetComponent<EndCollider>();
}
void Update()
{
if (MonsterShow.isShow == true)
{
float movementSpeed = 10f;
transform.position += transform.forward * Time.deltaTime * movementSpeed;
}
}
}
Now the code doesn't work, the code where move the monster works if I take them out the IF statement. I also keep getting this error NullReferenceException: Object reference not set to an instance of an object on the line if (MonsterShow.isShow == true)
Please help I'm a beginner to Unity and this problem stuck on me for so many hours now, I've done a lot Google searches and modified my code again and again but just can't solve this problem, I feel anxious and just don't know what to do.

Your find troll call in the Start() method is not finding the troll or not finding the EndCollider component on it, resulting in it being null. And since you only search once at startup it will always be null.
This is probably because your troll is not yet created at the start of the scene.
If your intent is actually to make the monster appear when the player hit the collider, you should look at Prefab Instantiation.
http://docs.unity3d.com/Manual/InstantiatingPrefabs.html
So in your OnTriggerEnter, you can simply instantiate a brand new monster:
public class EndCollider : MonoBehaviour {
public GameObject MonsterPrefab;
void OnTriggerEnter ()
{
Instantiate(MonsterPrefab);
}
}

One better way of communicating data between two scenes might be using PlayerPrefs:
//EndCollider.cs
public bool isShown
{
get { return PlayerPrefs.GetInt("IS_SHOWN")==1? true:false; }
set { PlayerPrefs.SetInt("IS_SHOWN", Convert.ToInt32(value));}
}
//SlowDownRun.cs
if(PlayerPrefs.GetInt("IS_SHOWN")==1) // isShown = true
{
...
}

Make masterShow endcollider public
clean your start method.
Just drag and drop the troll object from hierarchy to your script.
public class SlowDownRun : MonoBehaviour {
public EndCollider MonsterShow;
// Use this for initialization
void Start ()
{
}
void Update()
{
if (MonsterShow.isShow == true)
{
float movementSpeed = 10f;
transform.position += transform.forward * Time.deltaTime * movementSpeed;
}
}
}

Related

reference from various scripts causing problems [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
For some reason when I'm in the normal view in-game I am able to link the scripts that I need to call in order to make an animation like so
however, whenever I start the game it automatically removes them from the slots, and it doesn't work
I am completely clueless as to why this may be happening and unity keep giving me errors that say that I'm not setting an instance to my script I really have no clue why this may be happening.
I have 3 scripts that I'm working with that is giving me the problem
one is the main script for the enemy vision (I am referencing the other scripts in this one)
the second is the enemy animation script which makes him go from idle to attack and the third is an animation for the gun model since I had to make it follow the hands of the enemy
scripts attached bellow
1st script(enemyAI):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAi : MonoBehaviour
{
public bool detected;
GameObject target;
public Transform enemy;
public GameObject Bullet;
public Transform shootPoint;
public float shootSpeed = 10f;
public float timeToShoot = 1f;
public EnemyAni Animation;
public GunAni GunAnimation;
void Start()
{
Animation = GetComponent<EnemyAni>();
GunAnimation = GetComponent<GunAni>();
}
public void Update()
{
//makes the enemy rotate on one axis
Vector3 lookDir = target.transform.position - transform.position;
lookDir.y = 0f;
//makes enemy look at the players position
if (detected)
{
enemy.LookAt(target.transform.position, Vector3.up);
enemy.rotation = Quaternion.LookRotation(lookDir, Vector3.up);
}
if (detected == true)
{
Animation.LookPlayer = true;
GunAnimation.ShootPlayer = true;
}
if (detected == false)
{
Animation.LookPlayer = false;
GunAnimation.ShootPlayer = false;
}
}
//detects the player
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
detected = true;
target = other.gameObject;
}
}
void OnTriggerExit(Collider other)
{
if (other.tag == "Player")
{
detected = false;
}
}
}
2nd Script (EnemyAnimation):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAni : MonoBehaviour
{
public Animator animator;
public bool LookPlayer;
public void Start()
{
animator = GetComponent<Animator>();
}
public void Update()
{
if (LookPlayer == true)
{
animator.SetBool("IsShootingStill", true);
}
else
{
animator.SetBool("IsShootingStill", false);
}
}
}
3rd script (GunAnimation):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunAni : MonoBehaviour
{
public Animator animator;
public bool ShootPlayer;
public void Start()
{
animator = GetComponent<Animator>();
}
public void Update()
{
if (ShootPlayer == true)
{
animator.SetBool("IsShooting", true);
}
else
{
animator.SetBool("IsShooting", false);
}
}
}
Your code:
void Start()
{
Animation = GetComponent<EnemyAni>();
GunAnimation = GetComponent<GunAni>();
}
Searches the GameObject that holds the EnemyAI script for EnemyAni and GunAni. If the GameObject doesn't have those it will return null.
Sounds like you want to remove that code.
Note that if the scripts exist on a child of that GameObject you will need to use GetComponentInChildren
There are some things to review, good practices:
GameObject target is private for C#, but it is better to put private before.
variable names like Bullet Animation GunAnimation should always begin with lowercase, because they might be confused with a Class Name (search in internet for CamelCase and PascalCase).
Name should be clear. EnemyAni Animation is not clear enough, because Animation maybe any animation (player, enemy, cube, car, etc.).
It is better enemyAnimation to be clear, as you did with GunAnimation (only just with lower case at beginning)
As slaw said, the Animation must be in the GO attached.
about last item
Let's say you have an empty GO (GameObject) called GameObject1 and you attach EnemyAi script to it.
In Runtime (when game mode begins), it will try to find Animation = GetComponent<EnemyAni>();, but it won't find it
Why?
Because GetComponent<> searches for the Component(Class) that is in the <> (in this case EnemyAni) in its GO (in this case, GameObject1), but the unique script attached to GameObject1 is EnemyAI.
So, you have 3 options:
Attach EnemyAni to GameObject1
Create another GO (for example, GameObjectEnemyAni), attach the script EnemyAni and drag and drop GameObjectEnemyAni to GameObject1 and delete Animation = GetComponent<EnemyAni>(); in Start
Keep in mind: if you leave that line of code, instead of getting the script EnemyAni from GameObjectEnemyAni, it will run the code Animation = GetComponent<EnemyAni>(); in Start, and obviously, it won't find it
Create events. It's a really good practice for avoiding code tight coupling, but that is more advanced stuff.

my variable doesn't change even that in the log its say the variable change [unity]

I have 1 script to PlayerMovement and one for powerUp I the power-up code I reference player movement to change the speed and change the bool named timer to true and I write that in log and when I touch the paper the speed doesn't change and the timer don't turn to true but in the log, its say that is yes
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
private float TargetPos;
public float Speed;
void Start()
{
}
// Update is called once per frame
void Update()
{
transform.position = new Vector2(TargetPos, transform.position.y);
}
public void right()
{
TargetPos = transform.position.x + Speed * Time.deltaTime;
}
public void left()
{
TargetPos = transform.position.x - Speed * Time.deltaTime;
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Powrups : MonoBehaviour
{
public PlayerMovement pm;
public float PowerUpActiveTime;
public float StartPowerUpActiveTime;
public float peperSpeed;
float NormalSpeed;
bool timer;
bool timerover;
private void OnTriggerEnter2D(Collider2D col)
{
if (col.name == "peper")
{
pm.Speed = peperSpeed;
timer = true;
Debug.Log("timerOn");
Debug.Log(pm.Speed);
Debug.Log(timer);
}
}
private void Update()
{
while(timer)
{
GameObject Pause = GameObject.Find("Pause");
PauseScript pausescript = Pause.GetComponent<PauseScript>();
if (!pausescript.pause)
{
PowerUpActiveTime -= Time.deltaTime;
if(PowerUpActiveTime <= 0 )
{
timerover = true;
}
if (timerover)
{
timer = false;
}
}
}
if (timerover)
{
PowerUpActiveTime = StartPowerUpActiveTime;
pm.Speed = NormalSpeed;
}
}
private void Start()
{
PowerUpActiveTime = StartPowerUpActiveTime;
timerover = false;
NormalSpeed = pm.Speed;
}
}
Your mistake is that while loop.
You are lucky that until now you probably have tested this always while not being in pause mode ;)
This while would completely freeze your app and the entire Unity Editor!
In general be extremely careful with while loops and nested conditions like here, where the exit condition might never be fulfilled!
What happens currently is that you are not in pause mode so this while loop gets activated and runs until timer is set to false .. completely within one single frame. That is the reason why to you it seems that the value is never true.
What you rather want anyway is that code block be executed once per frame.
And in particular in a frame based application like Unity also have some performance impacts in mind.
You shouldn't use Find and GetComponent repeatedly within Update but store and re-use the results.
So your code should rather be
// If possible already drag this in via the Inspector
[SerializeField] private PauseScript _pauseScript;
private void Start()
{
PowerUpActiveTime = StartPowerUpActiveTime;
timerover = false;
NormalSpeed = pm.Speed;
// Get this ONCE as fallback on runtime
if(!_pauseScript)
{
_pauseScript = GameObject.Find("Pause"). GetComponent<PauseScript>();
// Or simply use
//_pauseScript = FindObjectOfType<_pauseScript>();
}
}
private void Update()
{
if(timer)
{
if (!_pauseScript.pause)
{
PowerUpActiveTime -= Time.deltaTime;
if(PowerUpActiveTime <= 0 )
{
timer = false:
PowerUpActiveTime = StartPowerUpActiveTime;
pm.Speed = NormalSpeed;
}
}
}
}
Besides all that, you should rather not let an external power-up control your player values. I would rather go the other way round and have your player object have a component which checks into which power-up items you run and react to it accordingly.
So your power-up itself would actually only be a trigger without any clue if or how exactly the player will be influenced by it.

Unity Sword Collision Attack

Hey guys I want to make a sword attack. But I get the error of:
NullReferenceException: Object reference not set to an instance of an
object
These are my codes:
My weaponattack script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weaponattack : MonoBehaviour
{
Enemy Enemy;
public float power;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
}
public void OnTriggerEnter(Collider col)
{
if(col.tag == "Enemy")
{
var kılıc = GetComponent<Enemy>();
Enemy.currentHealt -= 10;
Enemy.TakeDamage();
Debug.Log("Düşman Vuruldu");
}
}
}
This is my Enemy Health scrpt:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour {
public float currentHealt;
public float maxHealth;
// Use this for initialization
void Start () {
currentHealt = maxHealth;
}
// Update is called once per frame
void Update () {
}
public void TakeDamage()
{
currentHealt -= 10;
if(currentHealt < 0)
{
die();
}
}
void die()
{
Destroy(gameObject);
}
}
Can you helo em I couldnt understan why these codes are not working why am I getting that error.
I think your problem is in this line here GetComponent<Enemy>(); This needs a game object to get the component of
Enemy = col.GetComponent<Enemy>();
Should be what you're doing
You also may have issue calling your variable Enemy exactly the same as your class Enemy, I would change this to Enemy enemy; and
enemy = col.GetComponent<Enemy>();
respectivley
It seems pretty straightforward. You don't assign an Enemy to Weaponattack and so it's barfing when you first reference Enemy (Enemy.currentHealt). Either make Enemy public or a SerializedField so you can assign it in the Inspector, or however else you want to get an Enemy into Weaponattack.
Also don't name your property the same name as your script (Enemy Enemy). Surprised you didn't get a compile error.
EDIT Based on comments:
Enemy enemy;
public void OnTriggerEnter(Collider col)
{
if(col.tag == "Enemy")
{
var kılıc = GetComponent<Enemy>();
kilic.currentHealt -= 10;
kilic.TakeDamage();
Debug.Log("Düşman Vuruldu");
}
}
This also assumes you have an Enemy attached to your Weaponattack (GetComponent)

Unity problem activating a function with parameters in camera from another script in GameObject Enemy

I have a script that makes the camera do a shake by putting a button because
It is a public access function, if I do it that way when placing a button it works well but what I cannot achieve is to call the function so that every time my player collides with an enemy he makes the shake. I hope you can help me.
The shake code in camera is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScreenShaker : MonoBehaviour {
private float shakeAmount = 0.5f;
private float shakeTime = 0.0f;
private Vector3 initialPosition;
private bool isScreenShaking = false;
void Update () {
if(shakeTime > 0)
{
this.transform.position = Random.insideUnitSphere * shakeAmount + initialPosition;
shakeTime -= Time.deltaTime;
}
else if(isScreenShaking)
{
isScreenShaking = false;
shakeTime = 0.0f;
this.transform.position = initialPosition;
}
}
public void ScreenShakeForTime(float time)
{
initialPosition = this.transform.position;
shakeTime = time;
isScreenShaking = true;
}
}
The enemy code is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ControladorEnemigoCirculoMediano : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
Here I don't know what to call the public void function ScreenShakeForTime (float time);
I already tried many things online but when my character comes into contact with the character, I don't do the shake in the camera.
}
}
}
You can create Unity-singleton in your ScreenShaker class like:
class ScreenShaker
{
public static ScreenShaker Instance {private set; get;};
void Awake() {
Instance = this;
}
}
And than from any place to call like:
ScreenShaker.Instance.ScreenShakeForTime(2f);
This is the easiest way, but maybe it's better to create standard singeleton(it's up to you).
And also don;t forget to destroy it on OnDestroy()
can you tell me in enemy game object collider isTrigger is enable or not
if it is not enable then use OnColliderEnter2D(Collision2D other){} for collision detection

How to change a boolean from another script C#

I have 2 script, playerMachanics and enemyBehavior. My enemyBehavior has a boolean that when the boolean is true it moves away from the player. Instead i'm getting the error: "object reference not set to an instance of an object".
I'm sure it means the script can't find the component but i can't quite figure out what's wrong.
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
// Start is called before the first frame update
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade == true)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter(Collision collision)
{
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = GetComponent<enemyBehavior>();
script.evade = script.evade == true;
}
}
}
I expected that the movementSpeed would go to -4 but now i'm just getting an error.
Calling getComponent by itself will look for the component attached to the parent object of the script, which is the player in this case I think. So it will always return null.
Add
Public GameObject enemy;
to the playerMechanics class and then go into the designer and drag the game object that has the enemyBehavior script attached into it. There are several problems with the onCollisionEnter method. Something like this
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "coin")
{
Destroy(collision.gameObject);
enemyBehavior script = enemy.GetComponent<enemyBehavior>();
script.evade = false;
}
}
should get you going in the right direction.
Is the enemy behavior on the player object? See here
enemyBehavior evade = gameObject.GetComponent<enemyBehavior>();
and here
enemyBehavior script = GetComponent<enemyBehavior>();
You need to implement a way to track which enemy instance you are grabbing. Do this by making a variable to hold the enemy script, or by using a singleton on the enemy script (if there is one enemy).
Variable:
public enemyBehaviour enemy;
Singleton:
(enemyBehaviour)
public static enemyBehaviour instance = null;
private static readonly object padLock = new object();
void Awake(){
lock(padLock){
if(instance == null)
instance = this;
}
}
(player)
enemyBehaviour.instance.evade = false;
Look up singletons if you want to learn more.
If I'm right, I think your game mechanics works like this: The player's objective is to collect coins. When they collect one, the enemy near it will come and evade the player.
If that's the case, you should use this:
public class enemyBehavior : MonoBehaviour
{
public bool evade = false;
public GameObject Player;
public float movementSpeed = 4;
void Start()
{
Player = GameObject.FindGameObjectWithTag("Player");
}
void Update()
{
transform.LookAt(Player.transform);
transform.position += transform.forward * movementSpeed * Time.deltaTime;
if (evade)
{
movementSpeed = -4;
}
}
}
public class playerMechanics : MonoBehaviour
{
[SerializeField] enemyBehvaior enemy;
void OnCollisionEnter(Collision collision)
{
if (collision.collider.name == "coin")
{
Destroy(collision.collider.gameObject);
enemy.evade = true;
}
}
}
In your code, you wrote 'collision.gameObject.' This refers to the object the script is attached to. If you want to reference to the object that we hit, use 'collision.collider'.
'[SerializeField]' is a unity attribute, which is used to make a field show up in the inspector without making it public.
Just a heads up, if you're using 2D, make sure the method is signatured 'OnCollisionEnter2D(Collision2D collision)'.
I hope I answered your question. :)

Categories

Resources