I have a script to position the player where fell off from the platform.
Platform Tracker.cs
public GameObject platformTrackerPoint;
public Vector3 platformTransform;
public PlayerMovement thePlayerMovement;
void Start()
{
platformTrackerPoint = GameObject.Find("PlatformTrackerPoint");
thePlayerMovement = FindObjectOfType<PlayerMovement>();
}
void Update()
{
if ((transform.position.x < platformTrackerPoint.transform.position.x) && thePlayerMovement.grounded)
{
platformTransform = gameObject.transform.position;
Debug.Log ("Plaform Transform =" + platformTransform);
}
}
As I debugged, platformTransform shows the value I need. But its not reflecting in the code below.
GameController.cs
public PlatformTracker thePlatformTracker;
public Vector3 tempPosition;
void Start () {
platformStartPoint = platformGenerator.position;
playerStartPoint = thePlayer.transform.position;
thePlatformTracker = FindObjectOfType<PlatformTracker>();
thePlayer = FindObjectOfType<PlayerMovement>();
}
public void RespawnPlayer()
{
thePlayer.transform.position = thePlatformTracker.platformTransform;
}
Your help is much appreciated. Please let me know if anything is not clear.
To access thePlatformTracker correctly, you need to use GetComponent. In GameController.cs Start() simply change:
thePlatformTracker = FindObjectOfType<PlatformTracker>();
To:
thePlatformTracker = GameObject.Find("").GetComponent<Platform Tracker>();
Be sure and add the game controller object name between the GameObject.Find("") quotation marks.
Then you should be able to access the platformTransform no problem since thePlatformTracker is now correctly referencing the script.
Related
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 2 months ago.
I am learning to use Unity, I am currently doing the "Personal 3D Gallery Project" , here is the link if you want to take a look at it: https://learn.unity.com/project/create-a-personal-3d-gallery-project-with-unity?uv=2019.4
However, instead of displaying works of art in my gallery, I am displaying planets and my objective is that when the player approaches one of the planets, a text with information about that given planet pops out. In order to this, I am using the proximity script provided in the Unity website with a few changes. Everything seems to be working fine but when I approach the planets the text does not show and I keep receiving this error:
NullReferenceException: Object reference not set to an instance of an object
Proximity.Start () (at Assets/Scripts/Proximity.cs:32)
Apparently the problem is on line 32 but I can't figure out what's causing it. I am going to be attaching images for a better understating of the problem and my code.
I would really appreciate your help since this is for a final project, thank you so much in advance.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Proximity : MonoBehaviour
{
public string newTitle;
public string newNumber;
public string newInfo;
private Transform other;
private Text myTitle;
private Text myNumber;
private Text myInfo;
private float dist;
private GameObject player;
private GameObject message1;
private GameObject message2;
private GameObject message3;
private bool check;
// Start is called before the first frame update
void Start()
{
player = GameObject.FindWithTag("Player");
other = player.GetComponent<Transform>();
message1 = GameObject.FindWithTag("PlanetTitle");
message2 = GameObject.FindWithTag("PlanetNumber");
message3 = GameObject.FindWithTag("PlanetInfo");
myTitle = message1.GetComponent<Text>();
myTitle.text = "";
myNumber = message2.GetComponent<Text>();
myNumber.text = "";
myInfo = message3.GetComponent<Text>();
myInfo.text = "";
check = false;
}
// Update is called once per frame
void Update()
{
if (other)
{
dist = Vector3.Distance(transform.position, other.position);
print("Distance to player: " + dist);
if (dist < 4)
{
myTitle.text = newTitle;
myNumber.text = newNumber;
myInfo.text = newInfo;
check = true;
}
if (dist > 4 && check == true)
{
Start();
}
}
}
}
This is what I'm trying to do
But this is how it looks when I approach the planet (or moon in this case)
Here is my inspector, just in case the issue could be there
I checked my code multiple times and compared it to the original, I think I made all the necessary changes but clearly there is something wrong with it.
myTitle is not initialised before you are setting the property text on it. Initialise it by assigning the required components in Awake.
void Awake()
{
player = GameObject.FindWithTag("Player");
other = player.GetComponent<Transform>();
message1 = GameObject.FindWithTag("PlanetTitle");
message2 = GameObject.FindWithTag("PlanetNumber");
message3 = GameObject.FindWithTag("PlanetInfo");
myTitle = message1.GetComponent<Text>();
myNumber = message2.GetComponent<Text>();
myInfo = message3.GetComponent<Text>();
}
void Start()
{
myTitle.text = "";
myNumber.text = "";
myInfo.text = "";
check = false;
}
I've searched around and I just can't get this to work. I think I just don't know the proper syntax, or just doesn't quite grasp the context.
I have a BombDrop script that holds a public int. I got this to work with public static, but Someone said that that is a really bad programming habit and that I should learn encapsulation. Here is what I wrote:
BombDrop script:
<!-- language: c# -->
public class BombDrop : MonoBehaviour {
public GameObject BombPrefab;
//Bombs that the player can drop
public int maxBombs = 1;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)){
if(maxBombs > 0){
DropBomb();
//telling in console current bombs
Debug.Log("maxBombs = " + maxBombs);
}
}
}
void DropBomb(){
// remove one bomb from the current maxBombs
maxBombs -= 1;
// spawn bomb prefab
Vector2 pos = transform.position;
pos.x = Mathf.Round(pos.x);
pos.y = Mathf.Round(pos.y);
Instantiate(BombPrefab, pos, Quaternion.identity);
}
}
So I want the Bomb script that's attached to the prefabgameobject Bombprefab to access the maxBombs integer in BombDrop, so that when the bomb is destroyed it adds + one to maxBombs in BombDrop.
And this is the Bomb script that needs the reference.
public class Bomb : MonoBehaviour {
// Time after which the bomb explodes
float time = 3.0f;
// Explosion Prefab
public GameObject explosion;
BoxCollider2D collider;
private BombDrop BombDropScript;
void Awake (){
BombDropScript = GetComponent<BombDrop> ();
}
void Start () {
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void OnTriggerExit2D(Collider2D other){
collider.isTrigger = false;
}
void Explode() {
// Remove Bomb from game
Destroy(gameObject);
// When bomb is destroyed add 1 to the max
// number of bombs you can drop simultaneously .
BombDropScript.maxBombs += 1;
// Spawn Explosion
Instantiate(explosion,
transform.position,
Quaternion.identity);
In the documentation it says that it should be something like
BombDropScript = otherGameObject.GetComponent<BombDrop>();
But that doesn't work. Maybe I just don't understand the syntax here. Is it suppose to say otherGameObject? Cause that doesn't do anything. I still get the error : "Object reference not set do an instance of an object" on my BombDropScript.maxBombs down in the explode()
You need to find the GameObject that contains the script Component that you plan to get a reference to. Make sure the GameObject is already in the scene, or Find will return null.
GameObject g = GameObject.Find("GameObject Name");
Then you can grab the script:
BombDrop bScript = g.GetComponent<BombDrop>();
Then you can access the variables and functions of the Script.
bScript.foo();
I just realized that I answered a very similar question the other day, check here:
Don't know how to get enemy's health
I'll expand a bit on your question since I already answered it.
What your code is doing is saying "Look within my GameObject for a BombDropScript, most of the time the script won't be attached to the same GameObject.
Also use a setter and getter for maxBombs.
public class BombDrop : MonoBehaviour
{
public void setMaxBombs(int amount)
{
maxBombs += amount;
}
public int getMaxBombs()
{
return maxBombs;
}
}
use it in start instead of awake and dont use Destroy(gameObject); you are destroying your game Object then you want something from it
void Start () {
BombDropScript =gameObject.GetComponent<BombDrop> ();
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void Explode() {
//..
//..
//at last
Destroy(gameObject);
}
if you want to access a script in another gameObject you should assign the game object via inspector and access it like that
public gameObject another;
void Start () {
BombDropScript =another.GetComponent<BombDrop> ();
}
Can Use this :
entBombDropScript.maxBombs += 1;
Before :
Destroy(gameObject);
I just want to say that you can increase the maxBombs value before Destroying the game object. it is necessary because, if you destroy game object first and then increases the value so at that time the reference of your script BombDropScript will be gone and you can not modify the value's in it.
I want to access the HorizontalAxis variable from the CarAgent component (of the Taxi gameobject).
It works fine when I try to access it from another gameobject, but when I try to access it in CarUserControl, which is also a Taxi component, it says that CarAgent doesn't exist.
This is the other gameobject's script and it works fine:
private float HorizontalAxis;
public void Start() {
HorizontalAxis = GameObject.Find("Taxi").GetComponent<CarAgent>().HorizontalAxis;
}
// Update is called once per frame
public void Update()
{
transform.rotation = new Quaternion(0, 0, HorizontalAxis, 360);
}
and this is the CarUserControl script:
private void Start()
{
HorizontalAxis = GameObject.Find("Taxi").GetComponent<CarAgent>().HorizontalAxis;
}
How can I access the HorizontalAxis variable in CarUserControl ?
EDIT: I tried to access other classes in this script and it doesn't work neither.
I got this script from the UnityStandardAssets/Vehicules/Car, so at the beginning, it is written:
namespace UnityStandardAssets.Vehicles.Car
{
[RequireComponent(typeof (CarController))]
public class CarUserControl : MonoBehaviour
{
I am new to unity and c# so does it change something. And if yes, how can I fix it?
Finally, the problem was that the CarUserControl was in the standard assets folder and that the CarAgent script was not in that folder. Apparently, the standard assets folder does not compilate at the same time as other folders. See more here!
Its likely that you are too low or too high in the gameobject chain.
Try
car = GetComponent<CarAgent>(this.parent);
OR
car = GetComponent<CarAgent>(this.child);
h = car.HorizontalAxis;
It's mainly because there are inconsistencies between the Update() (every frame) and the FixedUpdate() (every physics frame). Indeed a FixedUpdate can be called more than once for the same Update() frame, or not at all.
Unity's doc about Order of Execution explains it more.
Also, querying GetComponent<T> in loops is quite heavy. It is wiser to "cache" the reference in an Init method like Start() or Awake().
private HorizontalAxis hAxis;
public void Start(){
GameObject taxi = GameObject.Find("Taxi");
if(taxi != null){
hAxis = taxi.GetComponent<CarAgent>().HorizontalAxis;
}
}
public void Update(){
if(hAxis != null)
transform.rotation = new Quaternion(0, 0, hAxis, 360);
}
public void FixedUpdate(){
if(hAxis != null){
// Do only Physics related stuff: rigidbodies, raycast
// inputs and transform operations should stay in the Update()
}
}
I am using Unity3D to create a demo.
The demo is like this: Use the EasyTouch to control the movement of the gameobject named "Player" —— the plane.
After creating the EasyTouch, I create a C# script like this:
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
public float m_speed = 1;
protected Transform m_transform;
public MovePlayer m_movePlayer;
// Use this for initialization
void Start () {
m_transform = this.transform;
}
// Update is called once per frame
void Update () {
}
void OnEnable(){
Debug.Log ("OnEnable");
EasyJoystick.On_JoystickMoveStart += HandleOn_JoystickMoveStart;
EasyJoystick.On_JoystickMove += HandleOn_JoystickMove;
EasyJoystick.On_JoystickMoveEnd += HandleOn_JoystickMoveEnd;
}
void HandleOn_JoystickMoveStart (MovingJoystick move)
{
}
void HandleOn_JoystickMoveEnd (MovingJoystick move)
{
}
void HandleOn_JoystickMove (MovingJoystick move)
{
Debug.Log ("HandleOn_JoystickMove");
if (m_transform == null) {
m_transform = this.transform;
}
if (move.joystickName != "moveJoystick") {
Debug.Log ("return");
return;
}
float currentPositionX = this.gameObject.GetComponent<Transform> ().position.x;
float currentPositionZ = this.gameObject.GetComponent<Transform> ().position.z;
float joyPositionX = move.joystickAxis.x;
float joyPositionY = move.joystickAxis.y;
Debug.Log ("joyPositionX = " + joyPositionX + " joyPositionY = " + joyPositionY);
float moveh = joyPositionX / 10;
float movev = joyPositionY / 10;
this.m_transform.Translate (new Vector3 (-joyPositionX/10, 0, -joyPositionY/10));
}
}
When I start the game, the code worked fine, and the plane will be control.
Then I create the button by GUI.
When the button was clicked, the code Application.LoadLevel(0) will be called.And the level will restart.
But after I called Application.LoadLevel(0) to restart the game.
The plane will can not be control by the EasyTouch, and the Error message will appear:
MissingReferenceException: The object of type 'Player' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
I wonder at why the "Player" will be null.
The "Player" should be init after called Application.LoadLevel(0), doesn't it?
Preamble
I have never used this EasyTouch plugin (fortunately? :D). So I'll make an assumptions on what I see in your code. If I'm wrong — sorry :)
Answer
Take a look on this code:
void OnEnable(){
Debug.Log ("OnEnable");
EasyJoystick.On_JoystickMoveStart += HandleOn_JoystickMoveStart;
EasyJoystick.On_JoystickMove += HandleOn_JoystickMove;
EasyJoystick.On_JoystickMoveEnd += HandleOn_JoystickMoveEnd;
}
It looks like EasyJoystick is a static class. And you are subscribing to static events here. Then after calling Application.LoadLevel() the instance of your Player class marked as destroyed. But subscriptions don't go anywhere and once EasyJoystick fires one of the events (On_JoystickMoveStart, On_JoystickMove or On_JoystickMoveEnd) corresponding methods (HandleOn_JoystickMoveStart, HandleOn_JoystickMove or HandleOn_JoystickMoveEnd) are being invoked. This is why you get the exception. And it is probably thrown by this line (am I wrong? :)):
float currentPositionX = this.gameObject.GetComponent<Transform> ().position.x;
In order to fix the problem you need to unsubscribe Player instance(s) from the events mentioned before invoking Application.LoadLevel().
Side note
This:
float currentPositionX = this.gameObject.GetComponent<Transform> ().position.x;
can be rewritten as:
float currentPositionX = transform.position.x;
Though currentPositionX and currentPositionY are not used at all :D
Edit. How to unsubscribe
Something like this:
void OnDisable(){
Debug.Log ("OnDisable");
EasyJoystick.On_JoystickMoveStart –= HandleOn_JoystickMoveStart;
EasyJoystick.On_JoystickMove –= HandleOn_JoystickMove;
EasyJoystick.On_JoystickMoveEnd –= HandleOn_JoystickMoveEnd;
}
I'm having some problems with Unity. I'm trying to make it so that if an enemy collides with the player, the player loses a health point. My C# code is below.
before you look at the code, I wanted to say that the enemies are rigid bodies so that the object bullets can affect them. I made an extra capsule to be a part of the player body that can be a rigid body so that the code can detect the collision. Do you think that would work? I'm unsure if it's easier for a rigid body to detect another rigid-body collision or if it doesn't care.
public class playerhealth : MonoBehaviour {
private int curHealth;
private int playerLives;
public GUIText winText;
public GUIText healthText;
public GUIText livesText;
void Start() {
curHealth = 3;
playerLives = 3;
SetHealthText();
SetLivesText();
winText.text = "";
}
void FixedUpdate()
{
// where physics codes go
}
// HERE'S WHERE THE COLLISIONS STUFF IS
void OnCollisionEnter(Collider rigidbody) {
if (rigidbody.gameObject.tag == "Enemy") {
curHealth = curHealth - 1;
SetHealthText();
}
if (rigidbody.gameObject.tag == "reloader") {
playerLives = playerLives - 1;
SetLivesText();
}
}
// setting GUI TEXT and reloading level
void SetHealthText() {
healthText.text = "Health Points: " + curHealth.ToString();
if (curHealth <= 0) {
Application.LoadLevel("shootingworld");
playerLives = playerLives - 1;
}
if(curHealth >= 10) {
playerLives+= 1;
}
}
void SetLivesText() {
livesText.text = "Lives: " + playerLives.ToString();
if (playerLives <= 0) {
winText.text = "GAME OVER";
}
}
}
You're making a number of assumptions here, some of which are wrong. I'll try to point them out.
Adding a RigidBody to a gameobject is the right idea, but it's the Collider component that determines the shape and size of the object's collision. Consider adding a BoxCollider, SphereCollider or CapsuleCollider to both.
I assume you're having trouble getting the objects to actually collide, this may be the solution.
Also,
void OnCollisionEnter(Collider rigidbody){
The parameter you've named 'rigidbody' is not guaranteed to be a RigidBody component. According to documentation
The Collision class contains information about contact points, impact velocity etc.
The proper syntax for OnCollisionEnter has a Collision parameter, not a Collider.
To access the rigidbody on the Collider, you'd have to use getcomponent on the object found by the Collider and check if the RigidBody component exists. I'm not sure this is what you're after, but the misleading parameter name should be checked.
Anyway you've got the right idea regarding comparing a Collider's gameobject by tag. All you need to do is enforce the tag on the object, either in the editor or through code.
You are using this:
void OnCollisionEnter(Collider collision) {
}
Collider is used for Ontrigger...
Try this:
void OnCollisionEnter(Collision collision) {
}
Hope this help ! :)
You try to this may help full also
void OnCollisionEnter(Collision collision)
{
}
Documentation is :
http://docs.unity3d.com/Documentation/ScriptReference/Collider.OnCollisionEnter.html