My script for setting combattext give exception - c#

my TextManager script is like this
using UnityEngine;
using System.Collections;
public class TextManager : MonoBehaviour {
private static TextManager instance;
public RectTransform canvasTransform;
public GameObject textPrefab;
public float speed;
public Vector3 direction;
void Start() {
speed = 1f;
direction = (new Vector3(0,1,0));
}
public static TextManager Instance
{
get
{
if (instance == null)
{
instance = GameObject.FindObjectOfType<TextManager>();
}
return instance;
}
}
public void CreateText(Vector3 position)
{
GameObject sct = (GameObject)Instantiate(textPrefab, position, Quaternion.identity);
sct.transform.SetParent(canvasTransform);
sct.GetComponent<RectTransform>().localScale = new Vector3(0.08f, 0.08f, 0.08f);
sct.GetComponent<CombatText>().Initialize(speed, direction);
}
}
CombatText is like this
using System.Collections;
public class CombatText : MonoBehaviour {
private float speed;
private Vector3 direction;
private float fadeTime;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
float translation = speed * Time.deltaTime;
transform.Translate(direction * translation);
}
public void Initialize(float speed, Vector3 direction) {
this.speed = speed;
this.direction = direction;
}
}
this is how i call it TextManager.Instance.CreateText(transform.position);
i have no idea why it gives that NullReferenceException: Object reference not set to an instance of an object
TextManager.CreateText (Vector3 position) (at Assets/TextManager/TextManager.cs:37)
PlayerControl.Update () (at Assets/Player/PlayerControl.cs:35)
any tips?

In line 37 of TextManager class is: sct.GetComponent<CombatText>().Initialize(speed, direction);
The only thing that can be null in this line is GetComponent<CombatText>()
So to fix this. Attach in inpsector the CombatText component to textPrefab or add it in runtime: sct.AddComponent<CombatText>().Initialize(speed, direction);.

Related

C# Unity; Sending a variable to a method as a pointer/reference or similar instead of whatever value the variable has

I am trying to make a script that will display the direction of a force with an arrow. The arrow is a GameObject that is initialized at startup. Upon initialization the public static GameObject ForceArrowBase is set to the object that already exists. This object is then instantiated when calling CreateNewForceArrow.
The forceVector in the ForceArrow class should not be a value, but rather some sort of reference/pointer or something in that nature. So when forceArrow.forceVector = forceVector is being called in the CreateNewForceArrow method, it shouldn't set the value to be whatever the value is at that point in time. Rather, it should set it to refer to the part of the memory that holds the variable data of the caller.
So when WindForce's Wind.Data.Speed changes, the forceVector in the ForceArrow refers to the data point Wind.Data.Speed.
In a way, it would be: void ForceVector { get => Wind.Data.Speed; }. But of course, if the CreateNewForceArrow method was called by ForceCreatingScript2, then it should be: void ForceVector { get => instancedForceCreatingScript2.forceOutput; }
So, is there anyway to parse the variable in as a pointer-type-thingy rather than the value of the variable?
public class ForceArrow : MonoBehaviour {
public static GameObject ForceArrowBase;
private static bool _initialized = false;
public GameObject refObject;
public Vector3 forceVector;
public float force;
public void FixedUpdate() {
transform.rotation = Quaternion.LookRotation(forceVector);
}
public static void CreateNewForceArrow(string name, ref Vector3 forceVectorReference, GameObject forceObject) {
var forceArrowObject = Instantiate<GameObject>(ForceArrowBase);
var forceArrow = forceArrowObject.GetComponent<ForceArrow>();
forceArrowObject.transform.position = forceObject.transform.position;
forceArrowObject.gameObject.name = name + "_forceArrow";
forceArrow.forceVector = forceVectorReference;
forceArrow.refObject = forceObject;
}
}
public class ForceCreatingScript1 : MonoBehaviour {
public Vector3 forceVector;
void Start() {
ForceArrow.CreateNewForceArrow(name, ref forceVector, gameObject);
}
void FixedUpdate() {
forceVector *= 1.2f;
}
}
public class ForceCreatingScript2 : MonoBehaviour {
public Vector3 forceOutput;
void Start() {
ForceArrow.CreateNewForceArrow(name, ref forceOutput, gameObject);
}
void FixedUpdate() {
forceOutput *= 1.6f;
}
}
public class WindForce : MonoBehaviour {
void Start() {
ForceArrow.CreateNewForceArrow(name, ref Wind.Data.SpeedVector, gameObject);
}
void FixedUpdate() {
Wind.Data.Speed = Mathf.Clamp(Wind.Data.Speed + Wind.WindRandom(), 15, Wind.MaximumWindSpeed);
Wind.Data.SpeedVector = BISH_MathHelper.DegreeToVector3(Wind.Data.DegAngle);
Wind.Data.RadAngle = (Wind.Data.RadAngle + Wind.WindRandom() / 80f) * Mathf.Rad2Deg;
}
}
Thanks for any help!

Firing Projectiles in Unity

Im trying to build a weapon in a game using Unity. My bullets spawn but i cant seem to get the force to apply on instantiation to get them to actually fire.
My weapon script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Weapon : MonoBehaviour {
public Rigidbody2D projectile;
public float forceMultiplier;
public Vector2 direction;
public Transform firePoint;
private float timeBtwShots;
public float startTimeBtwShots;
public void Fire(float force, Vector2 direction)
{
Instantiate(projectile, firePoint.position, transform.rotation);
projectile.AddForce(direction * force);
}
// Update is called once per frame
void Update () {
if (timeBtwShots <= 0)
{
if (Input.GetKeyDown(KeyCode.Return))
{
Fire(forceMultiplier, direction);
timeBtwShots = startTimeBtwShots;
}
}
else
{
timeBtwShots -= Time.deltaTime;
}
}
}
You need to add the force to the spawned object and not the prefab.
Your code should be something like this:
public void Fire(float force, Vector2 direction)
{
Rigidbody2D proj = Instantiate(projectile, firePoint.position, transform.rotation);
proj.AddForce(direction * force);
}

When i destroy my object create new one in diffrent position

When i click on my mouse button and destroy GameObject i want to create new one on random position, i try instatiate and other methods but it didn't work can someone help me whit this?
public GameObject tapObject;
private float respawnTime = 1f;
public float xMin;
public float xMax;
public float yMin;
public float yMax;
void Start()
{
StartCoroutine(spawnEnemyTime());
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Destroy(tapObject);
}
}
private void RandomSpawnObject()
{
tapObject.transform.position = new Vector2(Random.Range(xMin, xMax), Random.Range(yMin, yMax));
}
IEnumerator spawnEnemyTime()
{
while (true)
{
yield return new WaitForSeconds(respawnTime);
RandomSpawnObject();
}
}
If you want to keep the same GameObject you can avoid destroying it, instead you can control if it's active or not. It should look like this:
Edit:
Using GameObject.SetActive()
public GameObject tapObject;
private float respawnTime = 1f;
public float xMin;
public float xMax;
public float yMin;
public float yMax;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
tapObject.SetActive(false);
StartCoroutine(spawnEnemyTime());
}
}
private void RandomSpawnObject()
{
tapObject.SetActive(true);
tapObject.transform.position = new Vector2(Random.Range(xMin, xMax), Random.Range(yMin, yMax));
}
IEnumerator spawnEnemyTime()
{
yield return new WaitForSeconds(respawnTime);
RandomSpawnObject();
}
Using GameObject.Instantiate()
public GameObject prefab;
public GameObject tapObject;
private float respawnTime = 1f;
public float xMin;
public float xMax;
public float yMin;
public float yMax;
void Start()
{
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
Destroy(tapObject);
StartCoroutine(spawnEnemyTime());
}
}
private void RandomSpawnObject()
{
tapObject = GameObject.Instantiate(prefab, new Vector2(Random.Range(xMin, xMax), Random.Range(yMin, yMax)), Quaternion.identity);
}
IEnumerator spawnEnemyTime()
{
yield return new WaitForSeconds(respawnTime);
RandomSpawnObject();
}
Note that when using GameObject.Instantiate(), you need to have a prefab attached.
The simple way to resolve your problem is to create a method and call it with a timer and in that method just use following code
Code
Vector3 position = new Vector3(Random.Range(-10.0f, 10.0f), 0, Random.Range(-10.0f, 10.0f));
Instantiate(prefab, position, Quaternion.identity);
Note
Instead of using the prefab use you can use the gameobject you are using in the application

Unity - How can I use a flag to decide whether all the objects rotate at once or each one individually?

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class SpinableObject
{
[SerializeField]
private Transform t;
[SerializeField]
private float rotationSpeed;
[SerializeField]
private float minSpeed;
[SerializeField]
private float maxSpeed;
[SerializeField]
private float speedRate;
private bool slowDown;
public void Rotate()
{
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
{
private bool slowDown = false;
private GameObject[] allPropellers;
public bool rotateAll = false;
public float rotationSpeed;
public float slowdownMax;
public float slowdownMin;
public SpinableObject[] objectsToRotate;
// Use this for initialization
void Start()
{
allPropellers = GameObject.FindGameObjectsWithTag("Propeller");
}
// Update is called once per frame
void Update()
{
if (rotateAll == false)
{
for (int i = 0; i < objectsToRotate.Length; i++)
{
objectsToRotate[i].Rotate();
}
}
else
{
objectsToRotate = new SpinableObject[allPropellers.Length];
for (int i = 0; i < allPropellers.Length; i++)
{
objectsToRotate[i].Rotate();
}
}
}
}
In the else in this part I want that all the objects will rotate with the global variables settings. And if the rotateAll is false each one will rotate with their own options settings.
objectsToRotate = new SpinableObject[allPropellers.Length];
for (int i = 0; i < allPropellers.Length; i++)
{
objectsToRotate[i].Rotate();
}
But here I'm only make instance for more places in the objectsToRotate they are all null. And I'm not sure using objectsToRotate is good to rotate them all at once.
Update: This is what i tried now:
I changed the SpinableObject script to:
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;
private bool rotateAll;
// Use this for initialization
void Start()
{
}
// Update is called once per frame
void Update()
{
var _objecttorotate = objectsToRotate[index];
_rotate.t = _objecttorotate.t;
_rotate.rotationSpeed = _objecttorotate.rotationSpeed;
_rotate.minSpeed = _objecttorotate.minSpeed;
_rotate.maxSpeed = _objecttorotate.maxSpeed;
_rotate.speedRate = _objecttorotate.speedRate;
_rotate.slowDown = _objecttorotate.slowDown;
index++;
}
}
And created a new script name Rotate:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Rotate : MonoBehaviour
{
public Transform t;
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;
t.Rotate(Vector3.forward, Time.deltaTime * rotationSpeed);
}
}
The idea is to feed the variables and settings in the script Rotate from the script SpinableObject.
But i messed it up it's not working and give me some null exception.
Is it a good way ? And how can i fix the scripts to work with each other so the SpinableObject will feed the Rotate with data.
This is how I would approach your problem.
I will define a global variable to determine if objects are rotating all at the same time or independently.
Then I will create a script called rotation and I will add it to each GameObject in your scene which will rotate.
In this script I will just include the
...
Update()
{
if (rotateAll == false)
{
Rotate(allProperties)
}else{
Rotate(particularProperties)
}
}
//Here you can implement the Rotate function passing the attributes you consider to make the rotation different for each case
...
And about global variables in Unity. One possible approach is to define a class like:
public static class GlobalVariables{
public static boolean rotationType;
}
Then you can access and modigy this variable from another script like:
GlobalVariables.rotationType = true;
if(GlobalVariables.rotationType){
...
}
After Edit:
I can´t really tell what you are doing wrong, but if there is a null exception it may be you are not calling properly from the script the gameObjects you want to rotate. It could be you are not linking them correctly in the inspector. If you have declare
public SpinableObject[] objectsToRotate;
It is possible you forgot to drag and drop in the inspector the GamesObjets into the array to populate it. But I can't be sure if the problem is just that.

My shooting script does not work after respawning

I have a character who is able to shoot; however, when the character dies and respawns he is unable to shoot and I get the error:
UnassignedReferenceException: The variable BulletTrailPrefab of Weapon has not been assigned.
You probably need to assign the BulletTrailPrefab variable of the Weapon script in the inspector.
UnityEngine.Object.Internal_InstantiateSingle (UnityEngine.Object data, Vector3 pos, Quaternion rot) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineObject.cs:74)
UnityEngine.Object.Instantiate (UnityEngine.Object original, Vector3 position, Quaternion rotation) (at C:/BuildAgent/work/d63dfc6385190b60/artifacts/EditorGenerated/UnityEngineObject.cs:84)
Weapon.Effect () (at Assets/Weapon.cs:64)
Weapon.Shoot () (at Assets/Weapon.cs:53)
Weapon.Update () (at Assets/Weapon.cs:33)
If someone can help me fixing this it would be greatly appreciated. I have tried lots of stuff however nothing appears to work.
My weapon script
using UnityEngine;
using System.Collections;
public class Weapon : MonoBehaviour {
public float fireRate = 0;
public float Damage = 10;
public LayerMask whatToHit;
public Transform target;
public Transform BulletTrailPrefab;
float timeToSpawnEffect = 0;
public float effectSpawnRate = 10;
float timeToFire = 0;
Transform firePoint;
float nextTimeToSearch = 0;
// Use this for initialization
void Awake () {
firePoint = transform.FindChild ("firePoint");
if (firePoint == null) {
Debug.LogError ("No firePoint? WHAT?!");
}
}
// Update is called once per frame
void Update () {
if (fireRate == 0) {
if (Input.GetButtonDown ("Fire1")) {
Shoot();
}
}
else {
if (Input.GetButton ("Fire1") && Time.time > timeToFire) {
timeToFire = Time.time + 1/fireRate;
Shoot();
}
}
if (target == null) {
FindBulletTrailPrefab ();
return;
}
}
void Shoot () {
Vector2 mousePosition = new Vector2 (Camera.main.ScreenToWorldPoint (Input.mousePosition).x, Camera.main.ScreenToWorldPoint(Input.mousePosition).y);
Vector2 firePointPosition = new Vector2 (firePoint.position.x, firePoint.position.y);
RaycastHit2D hit = Physics2D.Raycast (firePointPosition, mousePosition-firePointPosition, 100, whatToHit);
if (Time.time >= timeToSpawnEffect) {
Effect ();
timeToSpawnEffect = Time.time + 1/effectSpawnRate;
}
Debug.DrawLine (firePointPosition, (mousePosition-firePointPosition)*100, Color.cyan);
if (hit.collider != null) {
Debug.DrawLine (firePointPosition, hit.point, Color.red);
Debug.Log ("We hit " + hit.collider.name + " and did " + Damage + " damage.");
}
}
void Effect () {
Instantiate (BulletTrailPrefab, firePoint.position, firePoint.rotation);
}
void FindBulletTrailPrefab () {
if (nextTimeToSearch <= Time.time) {
GameObject searchResult = GameObject.FindGameObjectWithTag ("BulletTrail");
if (searchResult != null)
target = searchResult.transform;
nextTimeToSearch = Time.time + 0.5f;
}
}
}
My gamemaster script
using UnityEngine;
using System.Collections;
public class GameMaster : MonoBehaviour {
public static GameMaster gm;
void Start () {
if (gm == null) {
gm = GameObject.FindGameObjectWithTag ("GM").GetComponent<GameMaster>();
}
}
public Transform playerPrefab;
public Transform spawnPoint;
public int spawnDelay = 2;
public IEnumerator RespawnPlayer () {
Debug.Log ("TODO: Add waiting for spawn sound");
yield return new WaitForSeconds (spawnDelay);
Instantiate (playerPrefab, spawnPoint.position, spawnPoint.rotation);
Debug.Log ("TODO: Add Spawn Particles");
}
public static void KillPlayer (Player player) {
Destroy (player.gameObject);
gm.StartCoroutine (gm.RespawnPlayer());
}
}
My player script
using UnityEngine;
using System.Collections;
public class Player : MonoBehaviour {
[System.Serializable]
public class PlayerStats {
public int Health = 100;
}
public PlayerStats playerStats = new PlayerStats();
public int fallBoundary = -20;
void Update () {
if (transform.position.y <= fallBoundary)
DamagePlayer (9999999);
}
public void DamagePlayer (int damage) {
playerStats.Health -= damage;
if (playerStats.Health <= 0) {
GameMaster.KillPlayer(this);
}
}
}
Late answer for answering's sake! (Lovely!)
The reason it only happens after you respawn is because when you instantiate a new playerPrefab, the Weapon object (which presumably is part of your player prefab) does not have the assignments you had made in the editor—those assignments are only for the specific instances that were in the editor. You'll need to manually assign it at runtime in one of two ways:
1) When you respawn:
public IEnumerator RespawnPlayer () {
// ...
GameObject playerInstance = Instantiate (
playerPrefab,
spawnPoint.position,
spawnPoint.rotation) as GameObject;
Weapon weaponInstance = playerInstance.GetComponentInChildren<Weapon>;
weaponInstance.BulletTrailPrefab = /* prefab reference */;
// ...
}
2) In your Weapon script:
void Start () {
BulletTrailPrefab = /* prefab reference */;
}
But in either case you would have to have some way of referencing the prefab at runtime, such as putting a reference into the GameMaster script or using Resources.Load().
The error is quite clear. You have not assigned a prefab to your variable..
UnassignedReferenceException: The variable BulletTrailPrefab of Weapon
has not been assigned.
You probably need to assign the BulletTrailPrefab variable of the
Weapon script in the inspector.

Categories