Unity 2D: My laser script is getting stuck on an if statement and I don't know why - unity3d

I've been making a laser in my 2D platformer for the past day. I've made the arm follow to cursor perfectly however on the script for the weapon it self doesn't work. Here is my code
using UnityEngine;
using System.Collections;
public class Weapon : MonoBehaviour {
public float fireRate = 0;
public float Damage = 10;
public LayerMask whatToHit;
float timeToFire = 0;
Transform firePoint;
// Use this for initialization
void Awake () {
firePoint = transform.FindChild ("FirePoint");
if (firePoint == null) {
Debug.LogError ("No firePoint");
}
}
// 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();
}
}
}
void Shoot () {
Debug.Log ("Works");
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);
Debug.DrawLine (firePointPosition, (mousePosition-firePointPosition)*100, Color.cyan);
Debug.Log ("Works 2");
if (hit.collider != null) {
Debug.Log ("Work 3");
Debug.DrawLine (firePointPosition, hit.point, Color.red);
Debug.Log ("We hit " + hit.collider.name + " and did " + Damage + " damage.");
}
}
}
The if statement in void Shoot isn't working. The first two debug messages in void Shoot show up in the log however the two in the if statement don't and I have no idea why. Can anyone help?

Related

How to get OnTriggerStay to work on every frame?

so I have this code :
public class ball_physics : MonoBehaviour
{
public Rigidbody ball;
public open2close claw;
public Vector3 offset;
Rigidbody rb;
private float forceMultiplier = 20;
private bool isShoot;
Vector3 start_position;
public path path;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.Sleep();
start_position = transform.position;
}
void Update()
{
// *************
}
void Shoot(Vector3 Force)
{
if (isShoot)
{
print("isshot false");
return;
}
rb.AddForce(new Vector3(Force.x, Force.y,Force.z)* forceMultiplier);
isShoot = true;
path.Instance.HideLine();
}
private void OnTriggerStay(Collider ball)
{
if (isShoot)
{
return;
}
print("ontriggerstay");
if (claw.isClosed && claw.transform.gameObject.tag == "claw" )
{
print("claw");
//rb.Sleep();
transform.position = claw.rightClaw.transform.position + offset;
Vector3 forceInit = (start_position - transform.position);
path.Instance.UpdateTrajectory(forceInit * forceMultiplier, rb, transform.position);
}
}
private void OnTriggerExit(Collider ball)
{
if (claw.isClosed && claw.transform.gameObject.tag == "claw")
{
rb.WakeUp();
}
if (claw.isClosed == false)
{
Shoot(start_position - transform.position);
}
}
}
So on my other codes I have OnStayTrigger, which basically a clawhand grabs a ball and pulls. But this code is suppose to show a trajectory line and shoot. When I shoot the first time it works. But when I try again, The clawhand can grab the ball but it doesnt show the trajectory line nor shoots it. So im guessing this is the code that needs to be fixed. How can I make OnTriggerStay work all the time. I wouldnt want to change any code because it works perfectly. How can I just keep updating the OnTriggerstay so it can work?
At first glance it appears that You never set isShoot back to false, so it would never fire again because in OnTriggerStay you have it return if isShoot = true.

Making Enemy Follow and Shoot Randomly at a multiple gameobjects with tags

Greeting, My friend and I have been trying to solve a problem of the Enemy script. The tags are "Player" the Enemy does not follow or shoot randomly, it only follows one and the rest it doesn't read the Tags of the other Game objects.
Thank you for your assistance
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class EnemyFollowPlayer : MonoBehaviour
{
public float speed;
public float lineOfSite;
public float shootingRange;
public float fireRate = 1f;
private float nextFireTime;
public GameObject bullet;
public GameObject bulletParent;
public GameObject[] player;
private BlackthronpodPlayerX playerX;
void Update ()
{
EnemyS ();
}
// Use this for initialization
void Start ()
{
player = GameObject.FindGameObjectsWithTag("Player");
playerX = GameObject.FindGameObjectWithTag ("Player").GetComponent<BlackthronpodPlayerX>();
}
void EnemyS ()
{
foreach (GameObject PlayerX in player)
{
float distanceFromPlayer = Vector2.Distance (PlayerX.transform.position, transform.position);
if (distanceFromPlayer < lineOfSite && distanceFromPlayer > shootingRange)
{
transform.position = Vector2.MoveTowards (this.transform.position, PlayerX.transform.position, speed * Time.deltaTime);
}
else if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}
}
You say you want the closest player only so I would rather do something like e.g.
using System.Linq;
...
private bool TryGetClosestPlayer(out GameObject closest)
{
// Sort the players by their distance to this object
var playersSortedByDistance = player.OrderBy(p => ((Vector2)p.transform.position - (Vector2)transform.position).sqrMagnitude);
// Get the first entry -> smallest distance
closest = playersSortedByDistance.FirstOrDefault();
// Returns true if a closest player was found
// If this returns false it means there is no object tagged "Player" in your scene the moment "Start" was called
return closest;
}
void EnemyS ()
{
// Now only consider this one closest player and ignore the others
if(TryGetClosestPlayer (out var closestPlayer))
{
var distanceFromPlayer = Vector2.Distance (closestPlayer.transform.position, transform.position);
if (distanceFromPlayer < lineOfSite && distanceFromPlayer > shootingRange)
{
transform.position = Vector2.MoveTowards (this.transform.position, PlayerX.transform.position, speed * Time.deltaTime);
}
else if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}

Trying to add buff to my game

I'm new at programming. I started a Unity3D course at udemy, I already finished the course, but I'm trying to add a buff to my game. What I want is when my player gets that buff, his shot speed inscreases, I tried to do it but im getting this error when I collide with it
NullReferenceException: Object reference not set to an instance of an object
Powerup.OnTriggerEnter2D (UnityEngine.Collider2D other) (at Assets/Galaxy Shooter/Scripts/Powerup.cs:54)
EDIT
Album With usefull images
Player
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public bool canTripleShoot = false;
public bool movSpeedBoost = false;
public bool shield = false;
[SerializeField]
private GameObject _laserPrefabs;
[SerializeField]
private GameObject _tripleShootPrefab;
[SerializeField]
private GameObject _shieldGameObject;
[SerializeField]
private GameObject _explosionPrefab;
[SerializeField]
private float _speed = 5.0f;
[SerializeField]
private GameObject[] _engines;
[SerializeField]
private float _fireRate = 0.25f;
private float _canFire = 0.0f;
public int playerHp = 3;
public int _hitcount = 0;
private UIManager _uiManager;
private GameManager _gameManager;
private SpawnManager _spawnManager;
private AudioSource _audioSource;
// Use this for initialization
void Start () {
_audioSource = GetComponent<AudioSource>();
_spawnManager = GameObject.Find("Spawn_Manager").GetComponent<SpawnManager>();
_uiManager = GameObject.Find("Canvas").GetComponent<UIManager>();
_gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
transform.position = new Vector3(0, 0, 0);
if(_uiManager != null)
{
_uiManager.UpdateLives(playerHp);
}
if(_spawnManager != null)
{
_spawnManager.StartSpawn();
}
}
// Update is called once per frame
void Update ()
{
Movement();
//ativar ao pressionar espaço ou botão esquerdo do mouse
if (Input.GetKeyDown(KeyCode.Space) || Input.GetMouseButton(0))
{
Shoot();
}
}
//renderização e cooldown dos tiros
private void Shoot()
{
if (Time.time > _canFire)
{
_audioSource.Play();
if (canTripleShoot== true)
{
Instantiate(_tripleShootPrefab, transform.position, Quaternion.identity);
}
else
{
Instantiate(_laserPrefabs, transform.position + new Vector3(0, 0.95f, 0), Quaternion.identity);
}
_canFire = Time.time + _fireRate;
}
}
//calculo de dano
public void Damage()
{
if(shield == true)
{
shield = false;
_shieldGameObject.SetActive(false);
return;
}
_hitcount++;
if(_hitcount == 1)
{
_engines[0].SetActive(true);
}
if(_hitcount == 2)
{
_engines[1].SetActive(true);
}
playerHp--;
_uiManager.UpdateLives(playerHp);
if(playerHp < 1)
{
Instantiate(_explosionPrefab, transform.position, Quaternion.identity);
_gameManager.gameOver = true;
_uiManager.ShowTitleScreen();
Destroy(this.gameObject);
}
}
public void ShieldUp()
{
shield = true;
_shieldGameObject.SetActive(true);
}
//controle da velocidade de movimento e teleporte
private void Movement()
{
float controleHorizontal = Input.GetAxis("Horizontal");
float controleVertical = Input.GetAxis("Vertical");
//velocidade de movimento
if(movSpeedBoost == true)
{
transform.Translate(Vector3.up * _speed * controleVertical * Time.deltaTime * 2.0f);
transform.Translate(Vector3.right * _speed * controleHorizontal * Time.deltaTime * 2.0f);
}else
{
transform.Translate(Vector3.up * _speed * controleVertical * Time.deltaTime);
transform.Translate(Vector3.right * _speed * controleHorizontal * Time.deltaTime);
}
//limita jogar até o centro da tela
if (transform.position.y > 0)
{
transform.position = new Vector3(transform.position.x, 0, 0);
}
//limita jogar até a borda inferior
else if (transform.position.y < -4.2f)
{
transform.position = new Vector3(transform.position.x, -4.2f, 0);
}
//teleporta jogar se sair da tela na horizontal
else if (transform.position.x < -9.45f)
{
transform.position = new Vector3(9.45f, transform.position.y, 0);
}
else if (transform.position.x > 9.45f)
{
transform.position = new Vector3(-9.45f, transform.position.y, 0);
}
}
//duração triple shot
public IEnumerator TripleShotPowerDownRoutine()
{
yield return new WaitForSeconds(5.0f);
canTripleShoot = false;
}
public void TripleShotPowerUpOn()
{
canTripleShoot = true;
StartCoroutine(TripleShotPowerDownRoutine());
}
//duração boost de movimento
public IEnumerator MovSpeedBoostDownRoutine()
{
yield return new WaitForSeconds(5.0f);
movSpeedBoost = false;
}
//ativa boost de movimento e inicia contagem de duração
public void MovSpeedBoost()
{
movSpeedBoost = true;
StartCoroutine(MovSpeedBoostDownRoutine());
}
}
Laser
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Laser : MonoBehaviour {
[SerializeField]
public float _speed = 10.0f;
[SerializeField]
public bool _laserBoost = false;
// Use this for initialization
void Start () {
_laserBoost = false;
if (_laserBoost == true)
{
_speed = 100f;
}
}
// Update is called once per frame
void Update () {
//código gigante e dificil de decifrar ~irony
transform.Translate(Vector3.up * _speed * Time.deltaTime);
if (transform.position.y > 6f)
{
if(transform.parent != null)
{
Destroy(transform.parent.gameObject);
}
Destroy(gameObject);
}
}
public IEnumerator LaserBoostDuration()
{
yield return new WaitForSeconds(10f);
_laserBoost = false;
}
public void LaserBoost()
{
_laserBoost = true;
StartCoroutine(LaserBoostDuration());
}
}
Powerup
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Powerup : MonoBehaviour
{
[SerializeField]
private float _speed = 3.0f;
[SerializeField]
private int powerupID;
[SerializeField]
private AudioClip _clip;
// Update is called once per frame
void Update ()
{
//movimenta o powerup para baixo
transform.Translate(Vector3.down * _speed * Time.deltaTime);
//destroy o power ao sair da tela
if (transform.position.y <-7)
{
Destroy(this.gameObject);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
if(other.tag == "Player")
{
//acessa o player
Player player = other.GetComponent<Player>();
if(player != null)
{
if(powerupID == 0)
{
//ativa tripleshoot
player.TripleShotPowerUpOn();
}
else if(powerupID == 1)
{
//ativa speedboost
player.MovSpeedBoost();
}
else if(powerupID == 2)
{
//ativar shield
player.ShieldUp();
}
else if (powerupID == 3)
{
Laser laser = GameObject.Find("laser").GetComponent<Laser>();
laser.LaserBoost();
}
}
//detroy powerup
AudioSource.PlayClipAtPoint(_clip, transform.position);
Destroy(this.gameObject);
}
}
}
The error is occuring at
laser.LaserBoost();
One of the two:
1) you don't have a object named "laser" in Scene hierarchy;
2) this object exists but doesn't have a component of type Laser attached to it.
Edit: Now that I saw your image, I can confirm it is the case 1) above. You have a Prefab named "laser", but is doesn't exist in the Scene hierarchy. If you want it to come to existence only when needed, you must instantiate the Prefab in scene.
If you want to search for the Prefab by its name, there is a way, but you'll need to have a folder named Resources inside another named Assets... More info here
Instead, I suggest you another approach. First, you will need a reference to your Prefab in some object, depending on the logic of your program. You seem to have a GameManager class, there could be a good place. Add a new field inside there (if it is the case) like this:
[SerializeField]
public Laser laser
// (...)
Then, change the code that generates the error. GameObject.Find tries to find an object that already exists in scene. In your case, you want to instantiate a clone of a Prefab, by passing a reference to it. Something like this:
else if (powerupID == 3)
{
// I don't know for sure how can you access your GameManager in your program. I will suppose your player have a reference to it.
// You shall change the position depending on your game logic
Laser laserClone = (Laser) Instantiate(player.gameManager.laser, player.transform.position, player.transform.rotation);
laserClone.LaserBoost();
}
Now, select the object in Scene that will have the reference (again, I am supposing it is gameManager) to see its inspector, than fill the laser field with a reference to your Prefab that has a Laser component. Just be sure the clone object will be destroyed when it is not needed.
But... To be very honest, I don't think you will get the result you are expecting anyway. If what you want is just faster shoot rate, the way you're trying to do it now seems pretty convoluted to me. Why don't you do it just like the triple shoot you have? Add a flag inside your player, when it is true the fireRate value changes.

I don't see what is wrong with the script to instantiate a prefab

I don't see what's wrong with this code. It says that the variable projectileEnemy is not assigned to anything, even though i was going to assign to it the prefab through the inspector window but the inspector window won't update because there's an error.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Attack : MonoBehaviour {
public Transform playerPos = null;
private float playerDist;
public GameObject projectileEnemy = null;
private void Shoot()
{
GameObject projectileEnemy = Instantiate(projectileEnemy, transform.position, Quaternion.identity) as GameObject;
}
void Update () {
playerDist = playerPos.position.x - transform.position.x;
if (playerDist <= (3) && playerDist >= (-3))
{
Shoot();
if (playerDist < (0))
{
projectileEnemy.GetComponent<Rigidbody>().AddForce(transform.left * 10);
}
else
{
projectileEnemy.GetComponent<Rigidbody>().AddForce(transform.right * 10);
}
}
}
}
You must distinguish between the projectile you create (the clone) and the one you use to make a copy from (the prefab)
// Assin in the inspector the prefab of the projectile
public GameObject projectileEnemyPrefab ;
private GameObject projectileClone ;
private void Shoot()
{
// Clone the prefab to create the real projectile of the enemy which will be propelled
projectileClone = Instantiate(projectileEnemyPrefab , transform.position, Quaternion.identity) as GameObject;
}
void Update () {
playerDist = playerPos.position.x - transform.position.x;
if (playerDist <= (3) && playerDist >= (-3))
{
Shoot();
if (playerDist < (0))
{
// Propel the instantiated **clone**
projectileClone .GetComponent<Rigidbody>().AddForce(transform.left * 10);
}
else
{
// Propel the instantiated **clone**
projectileClone .GetComponent<Rigidbody>().AddForce(transform.right * 10);
}
}
}

Unity 3D - Collider bug in 2D

I have a problem with Unity 2D collider, shown in this video: https://youtu.be/AMof6lJNtNk
Red wall is "killing" me, but just after game start/respawn. I'm colliding with 2 walls (brick has smaller collider than red wall) and I'm dying, but if I first collide to brick, then to red wall I don't die. Why?
I don't want to die in either case.
using UnityEngine;
using System.Collections;
public class MovementScript : MonoBehaviour {
public float speed = 1.0f;
Vector3 spawn;
// Use this for initialization
void Start () {
GetComponent ().freezeRotation = true;
spawn = GetComponent ().transform.position;
}
// Update is called once per frame
void Update () {
//Debug.Log ("Vertical: " + Input.GetAxis ("Vertical"));
if (Input.GetAxis ("Vertical") > 0) {
GetComponent ().velocity = new Vector2 (0, 1)*speed;
} else if (Input.GetAxis ("Vertical") ().velocity = new Vector2 (0, -1)*speed;
}
if (Input.GetAxis ("Horizontal") > 0) {
GetComponent ().velocity = new Vector2 (1, 0)*speed;
} else if (Input.GetAxis ("Horizontal") ().velocity = new Vector2 (-1, 0)*speed;
}
}
void OnTriggerEnter2D (Collider2D col){
Debug.Log ("Koliduje!");
if (col.transform.tag == "Respawn") {
Debug.Log ("Skułeś się!");
GetComponent ().transform.position = spawn;
}
}
}