Unity only allow shoot when visible - c#

Well this is my Enemy Script:
public class Enemy : MonoBehaviour
{
public GameObject explosion;
public float speed;
public float shotDelay;
public GameObject enemyBomb;
public bool canShot;
public int pointValue = 30;
IEnumerator Start()
{
GetComponent<Rigidbody2D>().velocity = Vector2.right * speed;
if (canShot == false) yield break;
while (true)
{
for (int i = 0; i < transform.childCount; i++)
{
Instantiate(enemyBomb, transform.position, transform.rotation);
}
yield return new WaitForSeconds(shotDelay);
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
FindObjectOfType<Score>().AddPoint(pointValue);
Instantiate(explosion, transform.position, transform.rotation);
Destroy(gameObject);
}
private void OnBecameInvisible()
{
Destroy(gameObject);
}
}
The problem is, that the enemy shoots before he is visible so there is no chance to fight him. Is there a way how to check if the Enemy is visible or not?

maybe you should try to add a trigger - so when the enemy touches the trigger that's set around the player vision something (let's say isvisible = true) should be set to true and every time the enemy wants to shoot it checks if (isvisible == true){//shoot}. And when the enemy goes out of the trigger OnTriggerExit2D(Collider2D collision) it sets isvisible = false
I hope it will work for you.

Related

Collisions won't work with instantiated prefabs

Alright so I have a collision script which works as in if I collide a gameobject with another object with the script attached it does register a collision.
The collision script I am using:
private void OnCollisionEnter(Collision collision)
{
Debug.Log("collision registered");
}
However when I try to collided my instantiated prefabs with my object with my script attached a collision does not get registered.
Does anyone know why this is? I think it's to do with with the prefabs being a "Moveable" but I can't quite get to the bottom of the problem.
Script attached to the prefabs:
public class Moveable : MonoBehaviour
{
public float _speedMetersPerSecond = 50f;
public float resistance = 10f;
public float current = 0f;
public List<Moveable> moveables = new List<Moveable>();
private Vector3? _destination;
private Vector3 _startPosition;
private float _totalLerpDuration;
private float _elapsedLerpDuration;
private Action _onCompleteCallback;
public GameObject Electron;
public Transform Lightbulb;
public SliderChange SliderScript;
public VMT2Counter script2;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
// THE LIGHTBULB PART IS FOR THE SPAWN POINT SO DO NOT DELETE
Moveable NextOnPath = Instantiate(Electron, Lightbulb.position, Quaternion.identity).GetComponent<Moveable>();
moveables.Add(NextOnPath.GetComponent<Moveable>());
MoverController.instance.targets.Add(NextOnPath.GetComponent<Moveable>());
}
if (_destination.HasValue == false)
return;
if (_elapsedLerpDuration >= _totalLerpDuration && _totalLerpDuration > 0)
return;
_elapsedLerpDuration += Time.deltaTime;
float percent = (_elapsedLerpDuration / _totalLerpDuration);
transform.position = Vector3.Lerp(_startPosition, _destination.Value, percent);
if (_elapsedLerpDuration >= _totalLerpDuration)
_onCompleteCallback?.Invoke();
// resistance = SliderScript.slider.value;
// current = script2.PotentialDifference / resistance;
}
public void MoveTo(Vector3 destination, Action onComplete = null)
{
var distanceToNextWaypoint = Vector3.Distance(transform.position, destination);
_totalLerpDuration = distanceToNextWaypoint / _speedMetersPerSecond;
_startPosition = transform.position;
_destination = destination;
_elapsedLerpDuration = 0f;
_onCompleteCallback = onComplete;
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Resistor")
{
Debug.Log("lol");
_speedMetersPerSecond = 25f;
}
}
}
Another script which goes hand in hand with the Moveable script but is not attached to the prefab:
public class MoverController : MonoBehaviour
{
public List<Moveable> targets;
[SerializeField] private Moveable target;
private List<Transform> _waypoints;
private int _nextWaypointIndex;
public static MoverController instance;
void Awake()
{
if (instance == null)
{
instance = this;
}
else
{
Destroy(gameObject);
return;
}
DontDestroyOnLoad(gameObject);
}
private void OnEnable()
{
MoveToNextWaypoint();
}
private void MoveToNextWaypoint()
{
for (int i = 0; i < targets.Count; i++)
{
if (targets[i] == null) continue;
_waypoints = GetComponentsInChildren<Transform>().ToList();
_waypoints.RemoveAt(0);
var targetWaypointTransform = _waypoints[_nextWaypointIndex];
targets[i].MoveTo(targetWaypointTransform.position, MoveToNextWaypoint);
targets[i].transform.LookAt(_waypoints[_nextWaypointIndex].position);
_nextWaypointIndex++;
if (_nextWaypointIndex >= _waypoints.Count)
_nextWaypointIndex = 0;
}
}
}
[![A picture of the prefab][1]][1]
[1]: https://i.stack.imgur.com/uyuge.png*emphasized text*
Video which shows situation: https://clipchamp.com/watch/MXjnTKl2cqg
The collider is a trigger:
Collider A
Collider B
Event triggered
Collider
Collider
Collision
Collider
Trigger
Trigger
Trigger
Collider
Trigger
Trigger
Trigger
Trigger
To fix this problem, either uncheck the box for it to collide normally, or change your event handler to detect triggers instead of colliders:
private void OnTriggerEnter(Collider other) {
Debug.Log("collision registered");
}
See here for more https://docs.unity3d.com/ScriptReference/Collider.OnTriggerEnter.html :)
It is also worth pointing out that if neither of your objects have rigidbodies on, the event will not fire. If you need it to fire but don't want all of the rigidbody physics, you can add one but tick the isKinematic box.

Enemy Projectile Script Won't Shoot Closest Object

I Have been trying to figure out how the Enemy doesn't return multiple GameObjects it only returns one.Im not sure whether it is my Bullet script that it allows only one object to return. I'm currently trying to develop a Game with multiple players like Slither.io so I'm not sure if the performance is affected I would like to use (List Function) but dont know where to start and I'm using a later version Unity 2017.3.1f1. Much Appreciated for your help.The scripts are below.
public class RandomAIProjectile
{
private GameObject[] target;
public float speed;
Rigidbody2D bulletRB;
public GameObject explosionEffect;
// Find Targets Section.
void Start ()
{
if (target == null)
target = GameObject.FindGameObjectsWithTag("Player");
for (int i = 0; i < target.Length; i++)
{
bulletRB = GetComponent<Rigidbody2D> ();
Vector2 moveDir = (target[i].transform.position - transform.position).normalized * speed;
bulletRB.velocity = new Vector2 (moveDir.x, moveDir.y);
Destroy (this.gameObject, 2);
}
}
private void OnTriggerEnter2D(Collider2D other)
{
// Decoy Script To Destroy Players.
if (other.gameObject.GetComponent<BlackthronpodDiePlayer>() != null)
{
Destroy (other.gameObject);
Destroy (gameObject);
}
// Damage Effect.
if (other.gameObject.tag == "Player") {
Instantiate (explosionEffect, transform.position, Quaternion.identity);
Destroy(gameObject);
}
// Player (Bullet) Destroy Enemy.
if (other.CompareTag ("Bullet"))
{
Destroy (other.gameObject);
Destroy (gameObject);
}
}
}
Here is the Player Script
public class RandomAIEnemy
{
//Random Movement
public float speed;
public float waitTime;
public float startWaitTime;
public Transform moveSpots;
public float minX;
public float minY;
public float maxX;
public float maxY;
//Enemy AI Shooting
public float lineOfSite;
public float shootingRange;
public float fireRate = 1f;
private float nextFireTime;
public GameObject bullet;
public GameObject bulletParent;
// My Current Player
private BlackthronpodPlayerX playerX;
// Player AI
private GameObject[] player;
public GameObject blood;
Vector3 respawn = new Vector3 (-34f,0,0);
//Additional Info
void FixedUpdate ()
{
EnemyS ();
}
// Use this for initialization
void Start ()
{
//My Player AI Tag.
player = GameObject.FindGameObjectsWithTag("Player");
waitTime = startWaitTime;
//My Current Player Tag.
playerX = GameObject.FindGameObjectWithTag ("Player").GetComponent<BlackthronpodPlayerX>();
//Random Movement Reference
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
}
//Closest (My Player Including Player AI.)
private bool TryGetClosestPlayer(out GameObject closest)
{
var playersSortedByDistance = player.OrderBy(p => ((Vector2)p.transform.position - (Vector2)transform.position).sqrMagnitude);
closest = playersSortedByDistance.FirstOrDefault();
return closest;
}
void EnemyS ()
{
GameObject closestPlayer = null;
if(TryGetClosestPlayer (out closestPlayer))
{
var distanceFromPlayer = Vector2.Distance (closestPlayer.transform.position, transform.position);
if (distanceFromPlayer <= shootingRange && nextFireTime < Time.time)
{
Instantiate (bullet, bulletParent.transform.position, Quaternion.identity);
nextFireTime = Time.time + fireRate;
}
}
}
// Range And Shooting Boundary For Player Including Player AI.
private void OnDrawGizmosSelected ()
{
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere (transform.position, lineOfSite);
Gizmos.DrawWireSphere (transform.position, shootingRange);
}
// Random Movement (I).
void RandomMove ()
{
//Rotate Movement Of Enemy.
transform.position = Vector2.MoveTowards (transform.position, moveSpots.position, speed * Time.deltaTime);
if (Vector2.Distance (transform.position, moveSpots.position) < 0.2f)
{
if(waitTime <= 0)
{
moveSpots.position = new Vector2 (Random.Range (minX, maxX), Random.Range (minY, maxY));
waitTime = startWaitTime;
} else {
waitTime -= Time.deltaTime;
}
}
}
private void OnTriggerEnter2D(Collider2D collision)
{
// Damage Effect On Enemy.
if (collision.gameObject.tag.Equals ("Player"))
{
Instantiate(blood,transform.position, Quaternion.identity);
}
// My Players Health.
if (collision.CompareTag ("Player"))
{
playerX.health --;
Debug.Log(playerX.health);
Destroy(gameObject);
}
// Player Score Manager.
if (collision.tag == "Bullet")
{
Game.AddToScore(1);
Destroy(gameObject);
}
}
}
Make sure that you have Rigidbody2d attached on your enemy and player. And also, is there any error coming in the code?

State machine for a game object in Unity doesn't seem to be working. Instead of changing from "stagger" to "idle", it just keeps moving

So I'm developing my first game in Unity currently (following a series by Mister Taft on YouTube called "Make a game like Zelda using Unity and C#" and just finished the 19th video).
I've currently got a "Log" enemy and am working on a knockback feature. I've followed the way that it is approached in the series is by creating a state machine that changes the Log's state to "stagger" for a couple of seconds, then return it to "idle" so it can change itself to "walk."
Whenever I hit the Log, however, it gets stuck in the stagger state and drifts without stopping until it hits a collider (note it doesn't change back to idle/walk even when it does hit the collider). If I can hit the Log correctly, sometimes, the player will actually also drift in the opposite direction.
Relevant code:
public class Log : Enemy {
private Rigidbody2D myRigidBody;
public Transform target;
public float chaseRadius;
public float attackRadius;
public Transform homePosition;
public Animator anim;
// Use this for initialization
void Start () {
currentState = EnemyState.idle;
myRigidBody = GetComponent<Rigidbody2D> ();
anim = GetComponent<Animator> ();
target = GameObject.FindWithTag ("Player").transform;
}
// FixedUpdate is called by physics.
void FixedUpdate () {
CheckDistance ();
}
//Log finds and walks towards Player.
void CheckDistance(){
if (Vector3.Distance (target.position, transform.position) <= chaseRadius && Vector3.Distance (target.position, transform.position) > attackRadius
&& currentState != EnemyState.stagger)
{
Vector3 temp = Vector3.MoveTowards (transform.position, target.position, moveSpeed * Time.deltaTime);
myRigidBody.MovePosition (temp);
ChangeState (EnemyState.walk);
}
}
private void ChangeState(EnemyState newState){
if (currentState != newState)
{
currentState = newState;
}
}
}
public class Knockback : MonoBehaviour {
public float thrust;
public float knockTime;
private void OnTriggerEnter2D(Collider2D other){
if (other.gameObject.CompareTag ("breakable"))
{
other.GetComponent<Pot>().Smash();
}
if(other.gameObject.CompareTag("enemy"))
{
Rigidbody2D enemy = other.GetComponent<Rigidbody2D>();
if (enemy != null)
{
enemy.GetComponent<Enemy> ().currentState = EnemyState.stagger;
Vector2 difference = enemy.transform.position - transform.position;
difference = difference.normalized * thrust;
enemy.AddForce (difference, ForceMode2D.Impulse);
StartCoroutine (KnockCo (enemy));
}
}
}
private IEnumerator KnockCo(Rigidbody2D enemy){
if (enemy != null)
{
yield return new WaitForSeconds (knockTime);
enemy.velocity = Vector2.zero;
enemy.GetComponent<Enemy>().currentState = EnemyState.idle;
}
}
}
public enum EnemyState{
idle,
walk,
attack,
stagger
}
public class Enemy : MonoBehaviour {
public EnemyState currentState;
public int enemyHealth;
public string enemyName;
public int baseAttack;
public float moveSpeed;
}
I've tried to add an else statement after the void CheckDistance in Log.cs, but that resulted in the Log having jittery movement and jumping back along its path. I'm at a loss. Any help would be greatly appreciated!

Power-Ups increasing projectile stats

I am trying to increase the damage of the players fireball when a power up is picked up. I am getting an object reference error, I'm pretty sure this is due to the code being linked tot he player for the collision and the fireballs have their own script detailing their speed, damage etc.
Essentially I need a way to reference my fireball prefab (Called Bullet) so the code can access the 'damage' stat and increase it for a period of time.
The code for the power-up is:-
private void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("Player"))
{
Pickup(other);
}
}
void Pickup(Collider2D player)
{
Instantiate(pickupEffect, transform.position, transform.rotation);
Fire stats = GetComponent<Fire>();
stats.damage *= 2;
Destroy(gameObject);
}
}
**The code for the fireball prefabs (known as Fire) is:-**
public class Fire : MonoBehaviour
{
public Animator animator;
public float speed = 20f;
public int damage = 30;
public Rigidbody2D rb;
public GameObject FireEmbers;
public float liveTime = 1f;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
void OnTriggerEnter2D(Collider2D hitInfo)
{
Enemy enemy = hitInfo.GetComponent<Enemy>();
if (enemy != null)
{
enemy.TakeDamage(damage);
}
Destroy(gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
void Update()
{
liveTime -= Time.deltaTime;
if (liveTime <= 0)
{
Destroy(this.gameObject);
Instantiate(FireEmbers, transform.position, Quaternion.identity);
}
}
}
I actually resolved this by using scriptable objects instead of hard coding things into prefabs.

How do I stop enemies from spawning in Unity 3D?

I want to stop enemies from spawning when one of them hit the "finish" tag.
Here's the script which spawn enemies:
public class spawn : MonoBehaviour {
public GameObject enemy;
private float spawnpoint;
public float xlimit = 12f;
float spawnNewEnemyTimer = 1f;
void Start()
{
}
public void Update()
{
spawnNewEnemyTimer -= Time.deltaTime;
if (spawnNewEnemyTimer <= 0 )
{
spawnNewEnemyTimer = 3;
GameObject nemico = Instantiate(enemy);
}
}
Here's the script which make the enemies appear at random point and move:
public class nemici : MonoBehaviour {
float speed = 4f;
public GameObject enemy;
public float xlimit = 12f;
private float currentPosition;
public GameObject spawn;
bool endGame = false;
void Start()
{
if (endGame == false)
{
Vector3 newPosition = transform.position;
newPosition.x = Random.Range(-xlimit, xlimit);
transform.position = newPosition;
}
else if (endGame == true)
{
return;
}
}
void Update()
{
if (endGame == false)
{
//per farlo muovere verso il basso
Vector3 movimento = new Vector3(0f, -speed, 0f); //(x, y, z)
transform.position += movimento * Time.deltaTime;
}
else if (endGame == true)
{
return;
}
}
void OnTriggerEnter(Collider other)
{
if (other.tag == "Player")
{
Destroy(enemy);
}
else if (other.tag == "Finish")
{
Debug.Log("hai perso!");
endGame = true;
}
}
}
What's wrong with this code? Thanks!
The logic that spawns new enemies is in the spawn class. The logic that decides whether you should stop spawning enemies, resides on the enemy class.
You are succesfully setting the endgame boolean to true whenever you want enemies to stop spawning when they hit an object with the finish tag.
void OnTriggerEnter(Collider other){
if (other.tag == "Finish"){
Debug.Log("hai perso!");
endGame = true;
}
}
Great! But you are not actually using it to stop spawns.
So far this variable is local to each enemy. So if you include checks in the start and update functions, they will only activate for the specific enemy that touched touched the finish object. This is not what you want.
You want the Spawn class to check the endgame variable, and if it is active, to stop spawning enemies.
To do this you will have to somehow be able to access the endgame variable from Spawn, What I recommend is that you make the endGame variable a member of te Spawn class. And that you include a reference to the Spawn in each enemy.
All together it might look something like this:
public class Spawn: MonoBehaviour{
public boolean endgame = false;
GameObject nemico = Instantiate(Enemy);
nemico.ParentSpawn = this
}
public class Enemy: MonoBehaviour{
public Spawn spawn;
void OnTriggerEnter(Collider other){
if (other.tag == "Finish"){
Spawn.endGame = true;
}
}
}
And then you can use the endgame boolean from within Spawn to check if you should keep spawning enemies.

Categories

Resources