Prefab shares the same animation - c#

Okay, I have a gameobject that clones a prefab programmatically (like a tower defense game that spawns enemies), the prefab has an animator controller attached to it. My problem is that whatever animation is playing from 1 prefab, the others share the same animation. For example, one prefab is in attack animation the others will do the same animation, and I do not want that.
Here is the script of the prefab:
using System;
using UnityEngine;
using Random = UnityEngine.Random;
public class AICharacterControl : MonoBehaviour
{
public UnityEngine.AI.NavMeshAgent agent { get; private set; }
[SerializeField] private GameObject[] GameObjects; // target to aim for
Transform target;
Animator animator;
int velocity = 0;
Rigidbody rb;
LayerMask layer;
Collider collider;
private GameObject player;
private Transform playerPosition;
bool isMoving;
void Start()
{
animator = GetComponent<Animator>();
rb = GetComponent<Rigidbody>();
player = GameObject.FindGameObjectWithTag("Player");
agent = GetComponent<UnityEngine.AI.NavMeshAgent>();
int n = Random.Range(0, GameObjects.Length);
target = GameObjects[n].GetComponent<Transform>();
agent.SetDestination(target.position);
playerPosition = player.GetComponent<Transform>();
}
void Update()
{
if (Vector3.Distance(playerPosition.position, this.transform.position) < 10 && Vector3.Distance(playerPosition.position, this.transform.position) > 5 && player.transform.position.y < 6)
{
animator.SetBool("isMoving", true);
agent.SetDestination(playerPosition.position);
if (Vector3.Distance(playerPosition.position, this.transform.position) <= 5)
{
animator.SetBool("attack", true);
}
}
else if (playerPosition.transform.position.y > 6)
{
agent.SetDestination(target.position);
animator.SetBool("attack", false);
if (agent.remainingDistance > agent.stoppingDistance)
{
animator.SetBool("isMoving", true);
if (agent.remainingDistance <= 3)
{
isMoving = false;
}
}
}
}
This is the script of the game object that spawns the prefab:
public class SpawnScript : MonoBehaviour {
// Use this for initialization
public GameObject NavAgent;
public int TotalSpawned = 0;
public int spawnDelay = 2;
public int SpawnQuantity;
public int SpawnRemaining;
public bool invoke = true;
private float time;
void Start () {
SpawnRemaining = SpawnQuantity;
}
// Update is called once per frame
void Update() {
time += Time.deltaTime;
while (invoke == true && time >= spawnDelay)
{
GameObject spawner = Instantiate(NavAgent, this.transform.position, Quaternion.identity);
Invoke("SpawnAgent", spawnDelay);
TotalSpawned++;
time = 0;
if (TotalSpawned == SpawnQuantity)
{
SpawnRemaining--;
invoke = false;
}
}
}

The problem is in if (playerPosition.transform.position.y > 6). It checks if player's y position is greater than 6 and than attacks. Player's position is same across all the prefabs, you need to compare distance between player and prefab.

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.

GameObject not being removed from List?

I've tried 2/3 different ways of removing my gameObject from my List but none are working. When I debug the method the debug log is showing up as it should yet the gameobject still isn't removed from the list.
When my teammates kill an enemy I want the enemy to be removed from the list and then destroyed so I can continue to iterate through the List to find the closest enemy to begin attacking. Because the gameObject's are not being removed I get a null reference and i can loop through my for loop to check.
1st Script: List is created and used in a for loop, removing and destroying the enemy also occurs in here.
public class FriendlyManager : MonoBehaviour
{
public NavMeshAgent navMeshAgent;
public Transform player;
public static FriendlyManager singleton;
public float health;
public float minimumDistance;
public int damage;
public List<GameObject> enemies;
private GameObject enemy;
private GameObject enemyObj;
// animations
[SerializeField] Animator animator;
bool isAttacking;
bool isPatroling;
// attacking
[SerializeField] Transform attackPoint;
[SerializeField] public GameObject projectile;
public float timeBetweenAttacks;
bool alreadyAttacked;
private void Awake()
{
navMeshAgent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
enemyObj = new GameObject();
}
private void Start()
{
singleton = this;
isAttacking = false;
isPatroling = true;
animator.SetBool("isPatroling", true);
}
private void Update()
{
for(int i = 0; i < enemies.Count; i++)
{
if(Vector3.Distance(player.transform.position, enemies[i].transform.position) <= minimumDistance)
{
enemy = enemies[i];
Attacking(enemy);
}
}
}
private void Attacking(GameObject enemy)
{
// stop enemy movement.
navMeshAgent.SetDestination(transform.position);
enemyObj.transform.position = enemy.transform.position;
transform.LookAt(enemyObj.transform);
if (!alreadyAttacked)
{
isAttacking = true;
animator.SetBool("isAttacking", true);
animator.SetBool("isPatroling", false);
Rigidbody rb = Instantiate(projectile, attackPoint.position, Quaternion.identity).GetComponent<Rigidbody>();
rb.AddForce(transform.forward * 32f, ForceMode.Impulse);
alreadyAttacked = true;
Invoke(nameof(ResetAttack), timeBetweenAttacks);
}
}
private void ResetAttack()
{
alreadyAttacked = false;
animator.SetBool("isAttacking", false);
}
public void DestroyEnemy(GameObject enemy)
{
enemies.Remove(enemy);
Debug.Log("AHHHHHHH M GOING CRAZY");
Destroy(gameObject);
}
}
}
2nd Script: Deals with the damage and checks enemy's currentHealth. (I have to post it as an image because for Stack Overflow is being annoying.) ._.
Shouldn't it just be
Destroy(enemy);
and not
Destroy(gameObject);

How to make the bullets to be firing towards a target?

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShootBullets : MonoBehaviour
{
public float bulletDistance;
public bool automaticFire = false;
public float fireRate;
public Rigidbody bullet;
private float gunheat;
private bool shoot = false;
private GameObject bulletsParent;
private GameObject[] startpos;
// Start is called before the first frame update
void Start()
{
bulletsParent = GameObject.Find("Bullets");
startpos = GameObject.FindGameObjectsWithTag("Fire Point");
}
private void Fire()
{
for (int i = 0; i < startpos.Length; i++)
{
Rigidbody bulletClone = (Rigidbody)Instantiate(bullet, startpos[i].transform.position, startpos[i].transform.rotation, bulletsParent.transform);
bulletClone.velocity = transform.forward * bulletDistance;
Destroy(bulletClone.gameObject, 0.5f);
}
}
// Update is called once per frame
void FixedUpdate()
{
if (automaticFire == false)
{
if (Input.GetMouseButtonDown(0))
{
Fire();
}
}
else
{
if (shoot == true)
{
Fire();
shoot = false;
}
}
if (gunheat > 0) gunheat -= Time.deltaTime;
if (gunheat <= 0)
{
shoot = true;
gunheat = fireRate;
}
}
}
now the bullets firing up the air and i want the bullets to fire to a target with physics.
the main goal later is to make some kind of side mission where the player third person view should shoot on object and if and when hitting the object the object will fall down and then the player will be able to pick it up.

I am trying to do a score that increase on ball collision with brick

I am doing a game in Unity for a school project.
I need to increase the score when the ball collides with brick. What I am doing wrong please? Below is the code that I tried to use. Score starts at zero but never goes more than 1. Any help of how I can fix this issue please?
public class Brick : MonoBehaviour
{
public int hitPoint = 3;
public GameObject explosion;
public GameObject heart;
[Range(0f, 1f)]
public float percentage;
float randNum;
public float fallSpeed = 8.0f;
public Sprite OneHits;
public Sprite TwoHits;
public Sprite ThreeHits;
public Text ScoreText;
private int points;
GameObject ball;
void Start()
{
ball = GameObject.FindGameObjectWithTag("ball");
}
void Update()
{
ScoreText.text = "Score " + points ;
randNum = Random.Range(0f, 1f);
if (hitPoint == 1)
{
this.GetComponent<SpriteRenderer>().sprite = OneHits;
}
if (hitPoint == 2)
{
this.GetComponent<SpriteRenderer>().sprite = TwoHits;
}
if (hitPoint == 3)
{
this.GetComponent<SpriteRenderer>().sprite = ThreeHits;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "ball")
{
ball = collision.gameObject;
hitPoint--;
points++;
if (hitPoint <= 0)
{
Destroy(this.gameObject);
Instantiate(explosion, transform.position, transform.rotation);
if (randNum < percentage)
{
Instantiate(heart, transform.position, transform.rotation);
}
}
}
}
}
There are a couple of things wrong with your code.
If you destroy the game object the script is running on the script will stop, so I would move your destroy command to the end of your method.
I am guessing that you dont want points to be different for each brick, I would move points to another class called scoreboard or something. For the time being I made points static. This means that only one copy of this variable exists and if one brick adds a point it gets reflected across all bricks.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Test : MonoBehaviour
{
public int hitPoint = 3;
public GameObject explosion;
public GameObject heart;
[Range(0f, 1f)]
public float percentage;
float randNum;
public float fallSpeed = 8.0f;
public Sprite OneHits;
public Sprite TwoHits;
public Sprite ThreeHits;
public Text ScoreText;
public static int points;
GameObject ball;
void Start()
{
ball = GameObject.FindGameObjectWithTag("ball");
}
void Update()
{
ScoreText.text = "Score " + points;
randNum = Random.Range(0f, 1f);
if (hitPoint == 1)
{
this.GetComponent<SpriteRenderer>().sprite = OneHits;
}
if (hitPoint == 2)
{
this.GetComponent<SpriteRenderer>().sprite = TwoHits;
}
if (hitPoint == 3)
{
this.GetComponent<SpriteRenderer>().sprite = ThreeHits;
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag("ball"))
{
ball = collision.gameObject;
hitPoint--;
points++;
if (hitPoint <= 0)
{
Instantiate(explosion, transform.position, transform.rotation);
if (randNum < percentage)
{
Instantiate(heart, transform.position, transform.rotation);
}
Destroy(gameObject);
}
}
}
}

How to change player speed with public float from another script

Hey I am trying to change a float when my player collides with a object. I tried many ways of reference but only got null when trying to debug I came up with this so far. I want to get the gameobject that contains the player script meaning the player and after I want to get the component script tankmovement to change the variable in it.
Getting the null reference error in the powerups script line 79 reset function Tank=GameObject.FindWithTag("Player")
using System.Collections.Generic;
using UnityEngine;
public class PowerUp : MonoBehaviour {
public bool boosting = false;
public GameObject effect;
public AudioSource clip;
public GameObject Tank;
private void Start()
{
Tank = GameObject.Find("Tank(Clone)");
TankMovement script = GetComponent<TankMovement>();
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
clip.Play();
GameObject explosion = Instantiate(effect, transform.position, transform.rotation);
Destroy(explosion, 2);
GetComponent<MeshRenderer>().enabled = false;
GetComponent<Collider>().enabled = false;
Tank.GetComponent<TankMovement>().m_Speed = 20f;
//TankMovement.m_Speed = 20f;
boosting = true;
Debug.Log(boosting);
StartCoroutine(coolDown());
}
}
private IEnumerator coolDown()
{
if (boosting == true)
{
yield return new WaitForSeconds(4);
{
boosting = false;
GetComponent<MeshRenderer>().enabled = true;
GetComponent<Collider>().enabled = true;
Debug.Log(boosting);
// Destroy(gameObject);
}
}
}
void reset()
{
//TankMovement.m_Speed = 12f;
TankMovement collidedMovement = Tank.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 12f;
//TankMovement1.m_Speed1 = 12f;
}
}
}
Trying to call on my m_Speed float in the player script to boost the speed of my player when he collides with it. How would you get a proper reference since my player is a prefab.
Tank script
using UnityEngine;
public class TankMovement : MonoBehaviour
{
public int m_PlayerNumber = 1;
public float m_Speed = 12f;
public float m_TurnSpeed = 180f;
public AudioSource m_MovementAudio;
public AudioClip m_EngineIdling;
public AudioClip m_EngineDriving;
public float m_PitchRange = 0.2f;
private string m_MovementAxisName;
private string m_TurnAxisName;
private Rigidbody m_Rigidbody;
private float m_MovementInputValue;
private float m_TurnInputValue;
private float m_OriginalPitch;
private void Awake()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
private void OnEnable ()
{
m_Rigidbody.isKinematic = false;
m_MovementInputValue = 0f;
m_TurnInputValue = 0f;
}
private void OnDisable ()
{
m_Rigidbody.isKinematic = true;
}
private void Start()
{
m_MovementAxisName = "Vertical" + m_PlayerNumber;
m_TurnAxisName = "Horizontal" + m_PlayerNumber;
m_OriginalPitch = m_MovementAudio.pitch;
}
private void Update()
{
// Store the player's input and make sure the audio for the engine is playing.
m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
m_TurnInputValue = Input.GetAxis(m_TurnAxisName);
EngineAudio();
}
private void EngineAudio()
{
// Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing.
if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
{
if (m_MovementAudio.clip == m_EngineDriving)
{
m_MovementAudio.clip = m_EngineIdling;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
else
{
if (m_MovementAudio.clip == m_EngineIdling)
{
m_MovementAudio.clip = m_EngineDriving;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
}
private void FixedUpdate()
{
// Move and turn the tank.
Move();
Turn();
}
private void Move()
{
// Adjust the position of the tank based on the player's input.
Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
}
private void Turn()
{
// Adjust the rotation of the tank based on the player's input.
float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
Quaternion turnRotation = Quaternion.Euler(0f, turn, 0);
m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
}
}
Since the TankMovement component you need to access is attached to the GameObject that is colliding with the power, you can get the TankMovement component you need to change by using other.gameObject.GetComponent<TankMovement>():
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
// stuff
TankMovement collidedMovement = other.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 20f;
// more stuff
}
}
}

Categories

Resources