Unassigned variable in Unity - c#

I've just started learning Unity 2D with the "How to make a 2D game" course from Brackeys on YouTube about 3 hrs ago. I'm using Unity 2018.4.1f1 on Ubuntu 18.04, and because JS is not supported in my version so I have to use C# instead. But I've encountered this error on the third video: The variable mainCam of GameSetup has not been assigned. This is my code in C#:
GameSetup.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameSetup : MonoBehaviour
{
public Camera mainCam;
public BoxCollider2D topWall, bottomWall, leftWall, rightWall;
public Transform Player1, Player2;
// Start is called before the first frame update
void Start()
{
// topWall = GetComponent<BoxCollider2D>();
// mainCam = GetComponent<Camera>();
// If I uncomment this, there would be a new error: There is no 'Camera' attached to '_GM' game object, but a script is trying to access it.
}
// Update is called once per frame
void Update()
{
// Move each wall to its edge location
topWall.size = new Vector2(mainCam.ScreenToWorldPoint(new Vector3(Screen.width * 2.0f, 0f)).x, 1.0f);
topWall.offset = new Vector2(0f, mainCam.ScreenToWorldPoint(new Vector3(0f, Screen.width, 0f)).y + 0.5f);
}
}
With the help of Google, I've add rb2d.GetComponent<Rigibody2D>() in Start() from the script of the second video under and prevent the error (there are no Start() in the video)
PlayerControls.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControls : MonoBehaviour
{
public KeyCode moveUp, moveDown;
public float speed = 10;
private Rigidbody2D rb2d = new Rigidbody2D();
// Start is called before the first frame update
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKey(moveUp))
{
Vector3 v = rb2d.velocity;
v.y = speed;
rb2d.velocity = v;
// rb2d.velocity.y = speed;
}
else if (Input.GetKey(moveDown))
{
Vector3 v = rb2d.velocity;
v.y = speed * (-1);
rb2d.velocity = v;
}
else
{
Vector3 v = rb2d.velocity;
v.y = 0;
rb2d.velocity = v;
}
}
}
How can I fix the bug in GameSetup.cs ? I've done exactly what said in the video, but only changed the language from JS to C#

Either assign it null:
public Camera mainCam = null;
But you are most likely missing to attach a camera object to it in the Unity3D editor. Check your inspector and make sure that whatever object that is using this script(GameSetup.cs) has a camera object assigned to its public variable.
Should look something like this. You have to drag and drop a camera object to the Gameobject.

Related

2D character is not moving in Unity, using the keys. Script seems to be correct. Please verify the code and the Inspector

![This is how my Inspector looks like](inspector image)
And here's the script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NewBehaviourScript : MonoBehaviour
{
public float speed = 10f;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
float h = Input.GetAxis("Horizontal");
float v = Input.GetAxis("Vertical");
Vector2 Movement = Vector2.zero;
Movement.y = v;
Movement.x = h;
transform.Translate(Movement * speed * Time.deltaTime);
}
} // class
And no, increasing the speed to check if its just not moving really slow, did not help :(
You need to set correct value in inspector or in start funciton.
void Start()
{
speed = 10f;
}
inspector image

How can I add a rotation to my bullets when they are shot?

I haven't used rotation in a while so I can't remember how to do this. I am trying to make a random trajectory for my bullets and I want to add a random rotation but I don't know how to add the rotation. I commented in the script where the rotation should be added. I have tried adding + transform.rotation * Quaternion.Euler(0,rot, 0) but I got the error error CS0019: Operator '+' cannot be applied to operands of type 'Vector3' and 'Quaternion'. What could I add to make this work?
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;
public class Player : MonoBehaviour
{
public GameObject bulletPrefab;
public Camera playerCamera;
private Coroutine hasCourutineRunYet = null;
public int ammo = 300;
public Text Ammmo;
private float xPos;
private float zPos;
private float yPos;
private float rot;
// Update is called once per frame
void Update()
{
Ammmo.text = "Ammo: " + ammo.ToString();
if(Input.GetMouseButtonDown(0))
{
if (hasCourutineRunYet == null)
hasCourutineRunYet = StartCoroutine(BulletShot());
}
}
IEnumerator BulletShot()
{
xPos = Random.Range(-0.3f, 0.3f);
yPos = Random.Range(-0.3f, 0.3f);
zPos = Random.Range(-0.3f, 0.3f);
rot = Random.Range(-10.0f, 10.0f);
GameObject bulletObject = Instantiate(bulletPrefab);
bulletObject.transform.position = playerCamera.transform.position + playerCamera.transform.forward + new Vector3(xPos, yPos, zPos) ; // add rotation here
bulletObject.transform.forward = playerCamera.transform.forward;
yield return new WaitForSeconds(1.0f);
hasCourutineRunYet = null;
ammo--;
}
}
I would look into the transform.rotation.RotateAround function. With this, you can call your bullet's relative forward, and rotate around itself essentially
Code Below:
using UnityEngine;
//Attach this script to a GameObject to rotate around the target position.
public class Example : MonoBehaviour
{
//Assign a GameObject in the Inspector to rotate around
public GameObject target;
void Update()
{
// Spin the object around the target at 20 degrees/second.
transform.RotateAround(target.transform.position, Vector3.up, 20 * Time.deltaTime);
}
}
Here's a URL to the documentation: https://docs.unity3d.com/ScriptReference/Transform.RotateAround.html

Add a cooldown to a Shooting Script

I Have this simple scrip fot the player to shoot a prefab when clicking the "Disparo" button, in this case the left click. Now its broken because you can spam the click and shoot every second. I dont Know how to add a cooldown to this to make that you only can shoot every certain time.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
}
// Update is called once per frame
void Update()
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
}
}
}
One way to achieve what you want is to set a boolean to check if the process is in cooldown.
private bool isInCooldown = false;
Then in your if statement you can invoke a new method, after completing your computations. As explained in Unity docs Invoke method:
Invokes the method methodName in time seconds.
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
if(!isInCooldown){
//Your code here
Invoke("ResetCooldown", 2f);
isInCooldown = true;
}
}
And the ResetCooldown method is simply:
private void ResetCooldown () {
isInCooldown = false;
}
Hope this helps.
The script below sets the cool time easily. You can set the cooldown time by changing shootcoolTime. and do not touch youCanShootNow. that variable only use to save time when you can shoot again;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
public class ProjectileShooter : MonoBehaviour
{
public AudioClip disparo;
GameObject prefab;
public float shootSpeed;
public float shootcoolTime;
float youCanShootNow;
// Start is called before the first frame update
void Start()
{
prefab = Resources.Load("Projectile") as GameObject;
youCanShootNow = 0;
}
public void Update()
{
if (youCanShootNow < Time.time)
{
if (CrossPlatformInputManager.GetButtonDown("Disparo"))
{
GameObject Projectile = Instantiate(prefab) as GameObject;
Projectile.transform.position = transform.position + Camera.main.transform.forward * 2;
Rigidbody rb = Projectile.GetComponent<Rigidbody>();
rb.velocity = Camera.main.transform.forward * shootSpeed;
Destroy(Projectile, 2.2f);
youCanShootNow = Time.time + coolTime;
}
}
}
}

transform.position not working properly in Unity

I am making a game in unity and i want to get the position of the player ( witch is a prefab ) so i use the code for the enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyScript : MonoBehaviour
{
public Transform player;
void Start()
{
Debug.Log(player.position.x);
}
}
I have a spawner and here is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnEnemies : MonoBehaviour
{
public GameObject enemy;
float randX;
float randY;
Vector2 whereToSpawn;
public float spawnRate = 2f;
float nextSpawn = 0.0f;
void Update()
{
if (Time.time > nextSpawn)
{
nextSpawn = Time.time + spawnRate;
randX = Random.Range(-6.36f, 6.36f);
randY = Random.Range(-4.99f, 4.99f);
whereToSpawn = new Vector2(randX, randY);
Instantiate (enemy, whereToSpawn, Quaternion.identity);
}
}
}
But when i run it, it always gives me (0, 0, 0). Why do i get 0 and how can i fix it ( get the current position of the player )?
Try with
Vector3 position = transform.position;
debug.log(position.x);
you can see more here Transform.position
You Debug.Log() the transform.position only once at the very start when the scene is loaded. Is it possible your object always starts there at 0,0,0 and then moves? If this is the case you are printing it's start position but never updating it. Try printing it on a key press of just every frame by putting it in Update(){}.
If that doesn't work, perhaps your object is nested within another? If so could help narrow down your issue by debug logging both transform.position and transform.localPosition?

Unity 3D How to setup Turret Auto Aim? C#

what i't trying to achieve is have my turrent rotate and follow an "Enemy".
At the moment it detects the enemy but it is not rotating and I don't know why.
The bullet it a prefab i drag in, there has to be a better way to do this? Anyone have any suggestions please?
At the moment the bullet never triggers, but the log Shoot and does...and the rotate doesn't work.
Here is what i have
using UnityEngine;
using System.Collections;
public class TurretController : MonoBehaviour {
public Rigidbody bulletPrefab;
private Transform target;
private GameObject bullet;
private float nextFire;
private Quaternion targetPos;
void OnTriggerEnter(Collider otherCollider) {
if (otherCollider.CompareTag("Enemy"))
{
Debug.Log ("in");
target = otherCollider.transform;
StartCoroutine ("Fire");
}
}
void OnTriggerExit(Collider otherCollider) {
if (otherCollider.CompareTag("Enemy"))
{
Debug.Log ("out");
target = null;
StopCoroutine("Fire"); // aborts the currently running Fire() coroutine
}
}
IEnumerator Fire()
{
while (target != null)
{
nextFire = Time.time + 0.5f;
while (Time.time < nextFire)
{
// smooth the moving of the turret
targetPos = Quaternion.LookRotation (target.position);
transform.rotation = Quaternion.Slerp(transform.rotation, targetPos, Time.deltaTime * 5);
yield return new WaitForEndOfFrame();
}
// fire!
Debug.Log ("shoot");
bullet = Instantiate(bulletPrefab, transform.position, transform.rotation) as GameObject;
//bullet.rigidbody.velocity = transform.forward * bulletSpeed;
}
}
}
I tried to change the instantiate part by using this instead
bullet = (GameObject)Instantiate(bulletPrefab, transform.position, transform.rotation);
bullet.GetComponent<Bullet>().target = target.transform;
But then i just get errors like "InvalidCastException: Cannot cast from source type to destination type.
TurretController+c__Iterator0.MoveNext () (at Assets/Scripts/TurretController.cs:44)"
BTW, here's the turret rotation code I used in my project (shared with permission):
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Turret : MonoBehaviour
{
[SerializeField]
private float turnRateRadians = 2 * Mathf.PI;
[SerializeField]
private Transform turretTop; // the gun part that rotates
[SerializeField]
private Transform bulletSpawnPoint;
private Enemy target;
void Update()
{
TargetEnemy();
}
void TargetEnemy()
{
if (target == null || target.health <= 0)
target = Enemy.GetClosestEnemy(turretTop, filter: enemy => enemy.health > 0);
if (target != null)
{
Vector3 targetDir = target.transform.position - transform.position;
// Rotating in 2D Plane...
targetDir.y = 0.0f;
targetDir = targetDir.normalized;
Vector3 currentDir = turretTop.forward;
currentDir = Vector3.RotateTowards(currentDir, targetDir, turnRateRadians*Time.deltaTime, 1.0f);
Quaternion qDir = new Quaternion();
qDir.SetLookRotation(currentDir, Vector3.up);
turretTop.rotation = qDir;
}
}
}
class Enemy : MonoBehaviour
{
public float health = 0;
private static HashSet<Enemy> allEnemies = new HashSet<Enemy>();
void Awake()
{
allEnemies.Add(this);
}
void OnDestroy()
{
allEnemies.Remove(this);
}
/// <summary>
/// Get the closest enemy to some transform, optionally filtering
/// (for example, enemies that aren't dead, or enemies of a certain type).
/// </summary>
public static Enemy GetClosestEnemy(Transform referenceTransform, System.Predicate<Enemy> filter=null)
{
// Left as an exercise for the reader.
// Remember not to use Vector3.Distance in a loop if you don't need it. ;-)
// return allEnemies[0];
}
}
First problem: the bullet prefab. The variable type is RigidBody. If you want to treat it as a game object, the variable must be a game object. Or you can instantiate it, cast to RigidBody, then use the .gameObject accessor. Like this:
((RigidBody)Instantiate(theRigidbody)).gameObject
Second problem: start simple with the rotation. If it's not working, don't get fancy yet. Start with something like this (an instant rotation toward the target):
Vector3 targetDirection = target.transform.position - transform.position;
targetDirection.y = 0; // optional: don't look up
transform.forward = targetDirection;
If it works, then add small pieces of additional complexity until it does exactly what you want. And if you don't get things figured out, give me a shout (a comment) on Monday. I've written turret-aiming code (including a maximum rotation speed), and I don't think my boss would mind if I upload it.

Categories