This question already has answers here:
Unity: Null while making new class instance
(2 answers)
Closed 5 years ago.
The first script is attached to a empty GameObject.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SpinableObject
{
public Transform t;
public float rotationSpeed;
public float minSpeed;
public float maxSpeed;
public float speedRate;
public bool slowDown;
}
public class SpinObject : MonoBehaviour
{
public SpinableObject[] objectsToRotate;
private Rotate _rotate;
private int index = 0;
// Use this for initialization
void Start()
{
_rotate = new Rotate>();
}
// Update is called once per frame
void Update()
{
var _objecttorotate = objectsToRotate[index];
_rotate.rotationSpeed = _objecttorotate.rotationSpeed;
_rotate.minSpeed = _objecttorotate.minSpeed;
_rotate.maxSpeed = _objecttorotate.maxSpeed;
_rotate.speedRate = _objecttorotate.speedRate;
_rotate.slowDown = _objecttorotate.slowDown;
}
}
The second script is attached to the GameObject/s i want to feed with information. So this script is attached to each GameObject separate.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public float rotationSpeed;
public float minSpeed;
public float maxSpeed;
public float speedRate;
public bool slowDown;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
RotateObject();
}
public void RotateObject()
{
if (rotationSpeed > maxSpeed)
slowDown = true;
else if (rotationSpeed < minSpeed)
slowDown = false;
rotationSpeed = (slowDown) ? rotationSpeed - 0.1f : rotationSpeed + 0.1f;
transform.Rotate(Vector3.forward, Time.deltaTime * rotationSpeed);
}
}
Not sure if this is a good way to what i want to do ?
Second problem is that the variable _rotate in the first script is all the time null:
I'm doing:
_rotate = new Rotate>();
But still here it's null:
_rotate.rotationSpeed = _objecttorotate.rotationSpeed;
I don't think you understand how Unity works.
First, _rotate = new Rotate>(); is not valid C# and will throw an error.
Second, in your case Rotate is a MonoBehaviour which is not attached to a GameObject. I think that whatever you tried to accomplish is maybe a step to far. You can' synchronize the Update-call of a deattached Component (of which I don't even know if it gets its Update-method called) with another object at all. In short: Your code seems nonsense to me.
I'd suggest, you move your RotateObject method into the SpinableObject and call it from SpinObject, instead of shoving stuff into _rotate. This should work.
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SpinableObject
{
public Transform t;
public float rotationSpeed;
public float minSpeed;
public float maxSpeed;
public float speedRate;
public bool slowDown;
public void RotateObject()
{
if (rotationSpeed > maxSpeed)
slowDown = true;
else if (rotationSpeed < minSpeed)
slowDown = false;
rotationSpeed = (slowDown) ? rotationSpeed - 0.1f : rotationSpeed + 0.1f;
t.Rotate(Vector3.forward, Time.deltaTime * rotationSpeed);
}
}
public class SpinObject : MonoBehaviour
{
[SerializeField]
private SpinableObject[] objectsToRotate;
// Update is called once per frame
void Update()
{
foreach(var spinner in objectsToRotate)
spinner.RotateObject();
}
}
Related
I am really new to unity and i'm trying to make a PlayerController with different states in different files.
this is the code so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
private PlayerState currentState;
void Start()
{
currentState = new PlayerIdle(this);
Cursor.lockState = CursorLockMode.Locked;
}
void Update()
{
currentState.OnStateUpdate();
}
public void ChangeState(PlayerState newState)
{
currentState.OnStateExit();
currentState = newState;
newState.OnStateEnter();
}
}
how do i fix this?
edit: here is the PlayerIdle code which is supposed to give me the error.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerIdle : PlayerState
{
public CharacterController controller;
public Transform cam;
public GameObject player = GameObject.Find("Player");
public float speed = 12f;
public float gravity = -9.81f;
public float jumpHeight = 3;
public float rotationSpeed;
float x;
float z;
public Transform groundCheck = GameObject.Find("groundCheck").transform;
public float groundDistance = 0.4f;
public LayerMask groundMask;
[SerializeField] Vector3 velocity;
public bool isGrounded;
public float turnSmoothTime = 1f;
float turnSmoothVelocity;
public PlayerIdle(PlayerController playerController) : base(playerController)
{
this.playerController = playerController;
}
public override void OnStateEnter()
{
}
public override void OnStateExit()
{
}
public override void OnStateUpdate()
{
x = Input.GetAxisRaw("Horizontal");
z = Input.GetAxis("Vertical");
isGrounded = Physics.CheckSphere(groundCheck.position, groundDistance, groundMask);
velocity = player.transform.TransformDirection(Vector3.forward) * speed * z + new Vector3(0f, velocity.y, 0f); ;
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2 * gravity);
}
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
velocity.y += gravity * Time.deltaTime;
player.transform.Rotate(new Vector3(0f, x * rotationSpeed, 0f));
controller.Move(velocity * Time.deltaTime);
}
}
any help would be much appreciated :)
also, i found out this is called a statemachine if that helps.
The error says that something in that line is null.
The only thing that can be null is the CurrentState variable.
Probably when you assign it the value of new PlayerIdle (this) in the Start () method, that value is null.
If you can figure out why it's null, you can fix it, but if you're still having trouble you can include the PlayerIdle () code.
A suggestion may be to insert a print (currentState) at the end of Start () to understand if it is actually null.
In addition, also insert a print (new PlayerIdel (this)) in the Update () method to understand if even during the update it continues to be null.
it seems that the update method was being called before the start method (which i still don't understand), so the solution was just to add an if statement before currentState.OnStateUpdate(); saying "if (currentState != null)"
I want to add 1 to a variable meters when ever 1 seconds passed. Task.Delay wont work for some reason.
Here is all my code. Unfortunely im only a beginner at csharp so if you want make you can give me feedback on how to make it better.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public int movementSpeed = 6;
private Rigidbody2D rb;
//the variable i want to add 1 to:
public int meters;
public double speeding = 5;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update()
{
Ymovement();
void Ymovement()
{
var movement = Input.GetAxis("Vertical");
transform.position += new Vector3(0, movement, 0) * Time.deltaTime * movementSpeed;
}
}
}
This is a pretty typical use case for InvokeRepeating:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class movement : MonoBehaviour
{
public int movementSpeed = 6;
private Rigidbody2D rb;
//the variable i want to add 1 to:
public int meters;
public double speeding = 5;
void Start()
{
rb = GetComponent<Rigidbody2D>();
InvokeRepeating("IncreaseMeters", 1f, 1f);
}
void Update()
{
Ymovement();
}
void Ymovement()
{
var movement = Input.GetAxis("Vertical");
transform.position += new Vector3(0, movement, 0) * Time.deltaTime * movementSpeed;
}
void IncreaseMeters()
{
meters += 1;
}
}
What I'm trying to do is have my player stop moving so I can play animation through a trigger-event or just a custscene.
What I expect was for one of them to trigger the timer then play animation>player move.. like a cut-scene
Also there are no errors In any of them They just didn't stop player from moving or just stop the player when starting the game(or when I press play it just set forwardMovement to 0)
Here's the code I use:
public class Player_controls : MonoBehaviour
{
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
public int forwardMovement = 1000;
public void Update()
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
}
Things that I tried:
public void ForwardMovement()
{
forwardMovement = 0;
Invoke("Action", 2f);
}
public void Action ()
{
forwardMovement = 1000 ;
}
Which only works for ForwardMovement(); method nothing else
I tried these two things also:
Public static class MonoExtensions
{
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public float Delayer = 10f;
public static class MonoExtensions
{
public static void Timed_delay(this MonoBehaviour mono,Action function, float Delayer)
{
mono.StartCoroutine(Timed_delayRoutine(function,Delayer));
}
static IEnumerator Timed_delayRoutine(Action function, float Delayer)
{
yield return new WaitForSeconds(Delayer);
function();
}
public class `Player_Controls`: MonoBehaviour
{
public void PM ()
{
forwardMovement = 0;
}
void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
this.Timed_delay(PM, Delayer);
}
}
}
Which just stop the player from moving an nothing else.
What I also tried was:
public class Player_Controls : MonoBehaviour
{
void Start()
{
StartCoroutine(ForwardMovement());
}
IEnumerator ForwardMovement()
{
forwardMovement = 0;
yield return new waitforseconds(Delayer);
forwardMovement = 1050;
}
void OnTriggerEnter(collider other)
{
if (CompareTag("Power_up"))
{
ForwardMovement();
}
}
}
Which did not work as in(it works but the timer part does nothing, so the player can't move when started the game )
Different way I tried
public class Player_Controls : MonoBehaviour
{
OnTriggerEnter(collider other)
{
Startcroutine(ForwardMovement ));
}
}
it didn't work but no Errors.
I tried this one by jazzhar:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if you're player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
It sorta works in a way if you set if
if (stopMoving == true)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
and
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = true;
}
then the player would be able to move but it will not trigger if hit the cube
it didn't work either but no Errors.
And some other timers I did but forgotten....
_________________________________________________________________March/6/21
public float Delayer = 10.0f;
I think found solution by doing this
private void OnTriggerEnter(Collider other)
{
if (CompareTag("Power_up"))
{
Delayer -= Time.deltaTime; <- this part giving me the error
if (Delayer => 0)
{
forwardMovement = 0;
}
}
}
but their one problem it giving me the this error Cannot convert lambda expression to type 'bool' because it is not a delegate type [Assembly-CSharp]csharp(CS1660) I don't know much about this even searching about doesn't help either
__________________________________________________________________March 28/21
this script is under player controls
this one works I made sure by doing Debug.Log("test");
void OnTriggerExit(Collider collision)
{
if (collision.gameObject.CompareTag("Power_up"))
{
forwardMovement = 0;
}
if (forwardMovement <= 0)
{
Debug.Log("test");
}
This might be a solution to you're problem, Fire-Source!:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class Player_controls : MonoBehaviour
{
// Drag the player in the inspector here;
public Rigidbody rb;
// Youre speed variable for movement.
public float Speed = 5;
// Youre speed variable for movement.
public int forwardMovement = 1000;
// Set this "stopmoving" bool to true to prevent movement.
public bool stopMoving = false;
// Create and select the right layer in the inspector.
public LayerMask WichObjectStopsMovement;
public void Update()
{
// if stopMoving = true than Dont Add force.
if (stopMoving == false)
{
rb.AddForce(0, 0, forwardMovement * Speed * Time.deltaTime);
}
}
private void OnCollisionEnter(Collision collision)
{
// if youre player touches a object and that object's layer
// is the same as "WichObjectStopsMovement" than disable Movement.
if (collision.collider.gameObject.layer == WichObjectStopsMovement)
{
stopMoving = false;
}
}
}
This code uses a LayerMask, to create 1 click on any object and in the inspector go:
Click on Layer:
Add Layer:
Write in User Layer 6, StopMovement (or anything else).
Than in the object that should stop player movement:
Click on layer:
Than select the Layer that says StopMovement.
And in you're player's script drag the object into the rb variable.
and in "WichObjectStopsMovement" assign the StopMovement layer.
This should take care of everything is that ok?
I have been trying to create a video game but I stuck in this tutorial, in the tutorial it shows us to use input actions addon (What that does is it makes W-A-S-D or joystick type of keys easy to use) but even I watched the video after 3rd time I couldn't find the mistake! the problem is that I am not able to move my player forward or backward, I can only move it right and left. Please help I have tried so many things, like restarting the program or changing some code but it's not working can you help me to fix it?
Here is the first code to take the WASD commands from the addon script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class InputManager : MonoBehaviour
{
//Takes the wasd controls from addon
InputWASD playerControls;
public Vector2 movementInput;
public float verticalInput;
public float horizontalInput;
private void OnEnable()
{
if (playerControls == null)
{
playerControls = new InputWASD();
playerControls.PlayerMovement.Movement.performed += i => movementInput = i.ReadValue<Vector2>();
}
playerControls.Enable();
}
private void OnDisable()
{
playerControls.Disable();
}
public void HandleAllInputs()
{
HandleMovementInput();
//TODO: HandleJumpInput
// HandleAttackInput
// HandleDashInput
// HandleAbilityInput
}
private void HandleMovementInput()
{
verticalInput = movementInput.y;
horizontalInput = movementInput.x;
}
}
Here is the second code to use keys in movement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAct : MonoBehaviour
{
InputManager inputManager;
Vector3 moveDirection;
Transform cameraObject;
Rigidbody playersRB;
public float moveSpeed = 6f;
public float rotationSpeed = 15f;
private void Awake()
{
inputManager = GetComponent<InputManager>();
playersRB = GetComponent<Rigidbody>();
cameraObject = Camera.main.transform;
}
public void HandleAllAction()
{
HandleMovement();
HandleRotation();
}
private void HandleMovement()
{
moveDirection = cameraObject.forward * inputManager.verticalInput;
moveDirection = moveDirection + cameraObject.right * inputManager.horizontalInput;
moveDirection.Normalize();
moveDirection.y = 0;
moveDirection = moveDirection * moveSpeed;
Vector2 movementVelocity = moveDirection;
playersRB.velocity = movementVelocity;
}
private void HandleRotation()
{
Vector3 targetDirection = Vector3.zero;
targetDirection = cameraObject.forward * inputManager.verticalInput;
targetDirection = targetDirection + cameraObject.right * inputManager.horizontalInput;
targetDirection.Normalize();
targetDirection.y = 0;
if (targetDirection == Vector3.zero)
{
targetDirection = transform.forward;
}
Quaternion targetRotation = Quaternion.LookRotation(targetDirection);
Quaternion playerRotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
transform.rotation = playerRotation;
}
}
Here is the third and last code to use first 2 codes:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMain : MonoBehaviour
{
//Calling scripts
InputManager inputManager;
PlayerAct playerAct;
private void Awake()
{
inputManager = GetComponent<InputManager>();
playerAct = GetComponent<PlayerAct>();
}
private void Update()
{
inputManager.HandleAllInputs();
}
private void FixedUpdate()
{
playerAct.HandleAllAction();
}
}
I did what the man told me (in the tutorial) but mine is not working!
sometime maybe the video is so old and unity is keep updating so some code maybe is not work anymore , maybe you should use the getinput system like float x= Input.GetAxis("Horizontal")); and float z = Input.GetAxis("Vertical"); this two is use characterController and let see how it work
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I need help, i'am trying to add float number from a script to another script but it does not work. I'am new to c# and coding in general if somebody code fix the script and explained whats wrong with this i would be very thankful. This is the error i am getting.
"NullReferenceException: Object reference not set to an instance of an object
Resources.Die () (at Assets/Resources.cs:42)
Resources.Update () (at Assets/Resources.cs:22)"
Here is my scripts:
1st
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour {
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start ()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update ()
{
Die();
}
public void OnMouseOver()
{
if(Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if(currentHealth <= 0)
{
Destroy(gameObject);
Inventory inventory = GetComponent<Inventory>();
inventory.ResourceStone = inventory.ResourceStone + 1;
}
}
}
2nd
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour {
public float ResourceStone;
// Use this for initialization
void Start ()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update () {
}
}
By looking at your code i think you never defined the inventory instance for your "resources" script. If you are using a getcomponent both the resources and the inventory script must be on the same gameobject to be found.
If what you want requires both scripts to be on other gameobjects you need a reference to the inventory in your resources script.
You can do this several way (like making a static reference and refering to it or defining inventory as a public variable and then adding the inventory reference in the unity editor)
This is how the first case would look:
First Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public static Inventory instance;
private void Awake()
{
instance = this;
}
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
}
Second Script -
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
Inventory.instance.ResourceStone++;
}
}
}
This is how the code would look if you did the second one:
first script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Inventory : MonoBehaviour
{
public float ResourceStone;
// Use this for initialization
void Start()
{
ResourceStone = 0;
}
// Update is called once per frame
void Update()
{
}
}
second script-
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Resources : MonoBehaviour
{
public float maxHealth = 5;
public float currentHealth;
public float ResourceCounter;
public Inventory inventory;
public Texture stoneIcon;
public Texture woodIcon;
void Start()
{
currentHealth = maxHealth;
ResourceCounter = 0;
}
void Update()
{
Die();
}
public void OnMouseOver()
{
if (Input.GetButtonDown("Fire1"))
{
Debug.Log("Loosing one health");
currentHealth = currentHealth - 1f;
}
}
public void Die()
{
if (currentHealth <= 0)
{
Destroy(gameObject);
inventory.ResourceStone++;
}
}
}
Just take in account two things to decide if you will use the first or the second one. The first one is a static reference, that means that you can't make more that one inventory. In the second one you need to manually drag the reference in the editor. Just in case you don't know, writing ++ after an integer does the same as integer = integer + 1;
EDIT: There, that's better looking :D