Question by
SimplyProves · 5 days ago ·
prefabsspawning problemsspawning-enemies
Enemy spawn from prefab cannot deal damage nor be damage by player
So I've read a similar post, tried it and it's not working. Basically I wanna make the game spawn enemy every 20 sec, but the spawned enemy is not dealing damage whatsoever and cannot be damaged. The enemy that I placed manually can is working properly tho. I have 2 type of enemy, archer and knight. The archer can damage the player (most probably because the arrow projectile is also a prefab) but cannot be damaged, the knight cannot do both. The player has a spell fireball that can damage the enemy (simillar to the arrow), and that's the only thing that can damage the enemy.
Here's the code
Player
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
public class PlayerController : MonoBehaviour
{
//Input System
private PlayerControlInput playerInput;
private InputAction movement;
public KnightController knightController;
public EnemyArcher archer;
//Movement and Physics
private Rigidbody rb;
[SerializeField]
private float moveForce = 1f;
[SerializeField]
private float maxSpeed = 5f;
private Vector3 forceDirection = Vector3.zero;
public Vector3 destination;
//Animation and Camera
[SerializeField]
private Camera playerCam;
private Animator animator;
//Audio
public GameObject playerWeapon;
public AudioClip lightAttackSound;
public AudioClip heavyAttackSound;
public AudioClip spellSound;
public AudioClip walkingSound;
//Player stats
public int playerHealth;
public int lightAttackDamage = 3;
public bool isLightAttacking = false;
public int heavyAttackDamage = 7;
public bool isHeavyAttacking = false;
public GameObject spell;
public Transform casterPostion;
public int spellDamage = 20;
public bool isSpellCasting = false;
public bool isAttacking = false;
public bool isPlayerBlocking = false;
public bool canCastSpell;
public bool canAttack;
public bool canBlock;
private float lightAttackCooldown = 1f;
private float heavyAttackCooldown = 2f;
private float parryCooldown = 1f;
private float spellCooldown = 5f;
public int totalEnemySlain;
public bool isDead;
private void Start()
{
knightController.enabled = true;
archer.enabled = true;
isDead = false;
playerHealth = 100;
totalEnemySlain = 0;
}
private void Awake()
{
rb = GetComponent<Rigidbody>();
playerInput = new PlayerControlInput();
animator = GetComponent<Animator>();
}
private void OnEnable()
{
movement = playerInput.Player.Movement;
movement.Enable();
playerInput.Player.Light_Attack.started += LightAttack;
playerInput.Player.Light_Attack.Enable();
playerInput.Player.Heavy_Attack.started += HeavyAttack;
playerInput.Player.Heavy_Attack.Enable();
playerInput.Player.Spell_Casting.performed += spellCast;
playerInput.Player.Spell_Casting.Enable();
playerInput.Player.Block.started += Blocking;
playerInput.Player.Block.Enable();
}
private void OnDisable()
{
movement.Disable();
playerInput.Player.Spell_Casting.Disable();
playerInput.Player.Light_Attack.started -= LightAttack;
playerInput.Player.Light_Attack.Disable();
playerInput.Player.Heavy_Attack.started += HeavyAttack;
playerInput.Player.Heavy_Attack.Disable();
playerInput.Player.Block.started -= Blocking;
playerInput.Player.Block.Disable();
}
#region Action Control
public void delayMove()
{
movement.Enable();
}
#region Blocking
public void Blocking(InputAction.CallbackContext obj)
{
isBlocking();
}
public void isBlocking()
{
canBlock = false;
isPlayerBlocking = true;
movement.Disable();
animator.SetTrigger("Blocking");
Invoke("delayMove", parryCooldown);
StartCoroutine(resetParryCoolDown());
}
IEnumerator resetParryCoolDown()
{
StartCoroutine(resetIsParrying());
yield return new WaitForSeconds(parryCooldown);
canBlock = true;
}
IEnumerator resetIsParrying()
{
yield return new WaitForSeconds(heavyAttackCooldown);
isPlayerBlocking = false;
}
#endregion
#region Heavy Attack
public void HeavyAttack(InputAction.CallbackContext obj)
{
if (canAttack)
{
heavyAttack();
}
}
public void heavyAttack()
{
isAttacking = true;
isHeavyAttacking = true;
canAttack = false;
movement.Disable();
animator.SetTrigger("HeavyAttack");
AudioSource heavyAudio = GetComponent<AudioSource>();
heavyAudio.PlayOneShot(heavyAttackSound);
Invoke("delayMove", heavyAttackCooldown);
StartCoroutine(resetHeavyAttackCoolDown());
}
IEnumerator resetHeavyAttackCoolDown()
{
StartCoroutine(resetIsHeavyAttacking());
yield return new WaitForSeconds(heavyAttackCooldown);
canAttack = true;
}
IEnumerator resetIsHeavyAttacking()
{
yield return new WaitForSeconds(heavyAttackCooldown);
isAttacking = false;
isHeavyAttacking = false;
}
#endregion
#region Light Attack
public void LightAttack(InputAction.CallbackContext obj)
{
if (canAttack)
{
lightAttack();
}
}
public void lightAttack()
{
isAttacking = true;
isLightAttacking = true;
canAttack = false;
movement.Disable();
animator.SetTrigger("LightAttack");
AudioSource lightAudio = GetComponent<AudioSource>();
lightAudio.PlayOneShot(lightAttackSound);
Invoke("delayMove", lightAttackCooldown);
StartCoroutine(resetLightAttackCoolDown());
}
IEnumerator resetLightAttackCoolDown()
{
StartCoroutine(resetIsLightAttacking());
yield return new WaitForSeconds(lightAttackCooldown);
canAttack = true;
}
IEnumerator resetIsLightAttacking()
{
yield return new WaitForSeconds(lightAttackCooldown);
isAttacking = false;
isLightAttacking = false;
}
#endregion
#region Spell
public void spellCast(InputAction.CallbackContext obj)
{
if (canCastSpell)
{
spellIsCasted();
}
}
public void spellIsCasted()
{
fireSpell();
isSpellCasting = true;
canCastSpell = false;
movement.Disable();
animator.SetTrigger("Casting");
AudioSource spellAudio = GetComponent<AudioSource>();
spellAudio.PlayOneShot(spellSound);
Invoke("delayMove", 1f);
StartCoroutine(resetSpellCoolDown());
}
IEnumerator resetSpellCoolDown()
{
StartCoroutine(resetisSpellCasting());
yield return new WaitForSeconds(spellCooldown);
canCastSpell = true;
}
IEnumerator resetisSpellCasting()
{
yield return new WaitForSeconds(1);
isSpellCasting = false;
}
public void fireSpell()
{
Ray ray = new Ray(casterPostion.position, casterPostion.forward);
RaycastHit hit;
if(Physics.Raycast(ray, out hit))
{
destination = hit.point;
}
else
{
destination = ray.GetPoint(10);
}
instantiateFire(casterPostion);
}
public void instantiateFire(Transform castingPoint)
{
GameObject fireball = Instantiate(spell, castingPoint.position, Quaternion.identity);
fireball.GetComponent<Rigidbody>().velocity = (destination - castingPoint.position).normalized * 30;
}
#endregion
public void hurt(int damage)
{
playerHealth -= damage;
}
public void dead()
{
if (playerHealth <= 0)
{
isDead = true;
animator.SetTrigger("Dead");
Debug.Log("Player is Dead");
knightController.enabled = false;
archer.enabled = false;
this.enabled = false;
Invoke("deathScene", 2f);
}
}
public void deathScene()
{
SceneManager.LoadScene("Death Scene");
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "Arrow" || collision.gameObject.tag == "Arrow")
{
playerHealth -= archer.attackDamage;
Debug.Log("Player struck by arrow!");
}
if (collision.gameObject.name == "Arrow" || collision.gameObject.tag == "Arrow" && isPlayerBlocking)
{
Debug.Log("Arrow parried!");
}
}
#endregion
#region Camera
private void lookingAt()
{
Vector3 direction = rb.velocity;
direction.y = 0;
if (movement.ReadValue<Vector2>().sqrMagnitude > 0.1f && direction.sqrMagnitude > 0.1f)
this.rb.rotation = Quaternion.LookRotation(direction, Vector3.up);
else
rb.angularVelocity = Vector3.zero;
}
private Vector3 GetCameraRight(Camera playerCam)
{
Vector3 right = playerCam.transform.right;
right.y = 0;
return right.normalized;
}
private Vector3 GetCameraForward(Camera playerCam)
{
Vector3 forward = playerCam.transform.forward;
forward.y = 0;
return forward.normalized;
}
#endregion
void FixedUpdate()
{
forceDirection += movement.ReadValue<Vector2>().x * GetCameraRight(playerCam) * moveForce;
forceDirection += movement.ReadValue<Vector2>().y * GetCameraForward(playerCam) * moveForce;
rb.AddForce(forceDirection, ForceMode.Impulse);
forceDirection = Vector3.zero;
Vector3 horizontalVelocity = rb.velocity;
horizontalVelocity.y = 0;
if (horizontalVelocity.sqrMagnitude > maxSpeed * maxSpeed)
rb.velocity = horizontalVelocity.normalized * maxSpeed + Vector3.up * rb.velocity.y;
lookingAt();
dead();
}
}
Collision Detection (on player sword)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CollisionDetection : MonoBehaviour
{
public PlayerController player;
public KnightController knight;
public EnemyArcher archer;
public AudioClip hit;
public AudioClip parried;
void OnTriggerEnter(Collider other)
{
if (other.tag == "Enemy" && player.isAttacking)
{
AudioSource isHitting = GetComponent<AudioSource>();
isHitting.PlayOneShot(hit);
if(other.name == "EnemyKnight")
{
if (player.isLightAttacking)
{
knight.takeDamage(player.lightAttackDamage);
Debug.Log("Light attack on " + other.name + " For " + player.lightAttackDamage);
}
if (player.isHeavyAttacking)
{
knight.takeDamage(player.heavyAttackDamage);
Debug.Log("Heavy attack on " + other.name + " For " + player.heavyAttackDamage);
}
}
if(other.name == "EnemyArcher"){
if(player.isLightAttacking)
{
archer.takeDamage(player.lightAttackDamage);
Debug.Log("Light attack on " + other.name + " For " + player.lightAttackDamage);
}
if (player.isHeavyAttacking)
{
archer.takeDamage(player.heavyAttackDamage);
Debug.Log("Heavy attack on " + other.name + " For " + player.heavyAttackDamage);
}
}
}
if(other.tag == "Blade")
{
if (player.isPlayerBlocking)
{
AudioSource parry = GetComponent<AudioSource>();
parry.PlayOneShot(parried);
Debug.Log("Parried");
}
}
}
}
Enemy Knight
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class KnightController : MonoBehaviour
{
//Enemy Stats
public int health;
public int attackDamage = 5;
public float attackCooldown = 1f;
public float agroRadius = 20f;
public bool canAttack;
public bool isAttacking = false;
public bool isDead;
//Enemy AI and Animation
public GameObject playerController;
Transform target;
NavMeshAgent agentKnight;
Animator animator;
void Start()
{
this.enabled = true;
isDead = false;
health = 20;
target = PlayerManager.instance.player.transform;
agentKnight = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
void Update()
{
float distance = Vector3.Distance(target.position, transform.position);
if (distance <= agroRadius)
{
isAgroedToPlayer();
if (distance <= agentKnight.stoppingDistance + 0.2f)
{
attackPlayer();
}
}
die();
}
#region Attack
public void attackPlayer()
{
isAttacking = true;
canAttack = false;
agentKnight.SetDestination(transform.position);
animator.SetBool("isAgro", false);
animator.SetTrigger("Attacking");
facePlayerWhenAttacking();
StartCoroutine(resetAttackCooldown());
}
IEnumerator resetAttackCooldown()
{
StartCoroutine(resetIsAttackingPlayer());
yield return new WaitForSeconds(attackCooldown);
canAttack = true;
}
IEnumerator resetIsAttackingPlayer()
{
yield return new WaitForSeconds(attackCooldown);
isAttacking = false;
}
#endregion
#region Agro
public void isAgroedToPlayer()
{
animator.SetBool("isAgro", true);
agentKnight.SetDestination(target.position);
}
#endregion
public void takeDamage(int damage)
{
health -= damage;
}
public void die()
{
if (health <= 0)
{
isDead = true;
animator.SetTrigger("Dead");
animator.SetBool("isAgro", false);
this.GetComponent<Rigidbody>().detectCollisions = false;
playerController.GetComponent<PlayerController>().totalEnemySlain += 1;
this.enabled = false;
Debug.Log("Knight Killed!");
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Fireball" || collision.gameObject.tag == "Spell")
{
health -= playerController.GetComponent<PlayerController>().spellDamage;
Debug.Log("Knight is struck by fireball for " + playerController.GetComponent<PlayerController>().spellDamage);
}
}
public void facePlayerWhenAttacking()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5);
}
}
Enemy Knight Collision (on knight sword)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KnightCollisionDetector : MonoBehaviour
{
public KnightController knight;
public PlayerController player;
public AudioClip playerHit;
private void OnTriggerEnter(Collider other)
{
if (other.tag == "Player" || other.name == "Player" && knight.GetComponent<KnightController>().isAttacking)
{
if (player.isPlayerBlocking)
{
Debug.Log("Parried");
}
AudioSource hit = GetComponent<AudioSource>();
hit.PlayOneShot(playerHit);
player.hurt(5);
Debug.Log("Knight hit player for " + 5);
}
}
}
Enemy Archer
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyArcher : MonoBehaviour
{
//Enemy Stats
public static int health;
public int attackDamage = 10;
public bool isAttacking = false;
public bool canAttack;
public float attackCooldown = 5f;
public float agroRadius = 50f;
public float bowRange = 30f;
public bool isDead = false;
//AI
public GameObject playerController;
public GameObject arrow;
public Transform arrowPoint;
Transform target;
NavMeshAgent agentArcher;
Animator animator;
void Start()
{
this.enabled = true;
isDead = false;
health = 10;
target = PlayerManager.instance.player.transform;
agentArcher = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
}
void Update()
{
float distance = Vector3.Distance(target.position, transform.position);
if (distance <= agroRadius)
{
isAgroedToPlayer();
if(distance <= agroRadius && distance >= bowRange)
{
animator.SetBool("inRange", false);
animator.SetTrigger("Attacking");
agentArcher.SetDestination(target.position);
}
if (distance <= bowRange)
{
attackPlayer();
}
}
die();
}
#region Attack
public void attackPlayer()
{
isAttacking = true;
canAttack = false;
agentArcher.SetDestination(transform.position);
animator.SetBool("isAgro", false);
animator.SetBool("inRange", true);
animator.SetTrigger("Attacking");
facePlayerWhenAttacking();
StartCoroutine(resetAttackCooldown());
}
IEnumerator resetAttackCooldown()
{
StartCoroutine(resetIsAttackingPlayer());
yield return new WaitForSeconds(attackCooldown);
canAttack = true;
}
IEnumerator resetIsAttackingPlayer()
{
yield return new WaitForSeconds(attackCooldown);
isAttacking = false;
}
public void shootArrow()
{
GameObject arrowProjectile = Instantiate(arrow, arrowPoint.position, transform.rotation);
arrowProjectile.GetComponent<Rigidbody>().AddForce(transform.forward * 25f, ForceMode.Impulse);
}
#endregion
#region Agro
public void isAgroedToPlayer()
{
animator.SetBool("isAgro", true);
agentArcher.SetDestination(target.position);
}
#endregion
public void takeDamage(int damage)
{
health -= damage;
}
public void die()
{
if(health <= 0)
{
isDead = true;
animator.SetTrigger("Dead");
animator.SetBool("isAgro", false);
this.GetComponent<Rigidbody>().detectCollisions = false;
playerController.GetComponent<PlayerController>().totalEnemySlain += 1;
this.enabled = false;
Debug.Log("Archer Killed!");
}
}
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.name == "Fireball" || collision.gameObject.tag == "Spell")
{
health -= playerController.GetComponent<PlayerController>().spellDamage;
Debug.Log("Archer is struck by fireball " + playerController.GetComponent<PlayerController>().spellDamage);
}
}
public void facePlayerWhenAttacking()
{
Vector3 direction = (target.position - transform.position).normalized;
Quaternion lookRotation = Quaternion.LookRotation(new Vector3(direction.x, 0, direction.z));
transform.rotation = Quaternion.Slerp(transform.rotation, lookRotation, Time.deltaTime * 5);
}
}
Arrow (for archer)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Arrow : MonoBehaviour
{
private void Start()
{
Destroy(gameObject, 10);
}
private void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.name == "Player" || collision.gameObject.tag == "Player")
{
Destroy(transform.GetComponent<Rigidbody>());
Destroy(gameObject);
}
}
}
Fireball (for player)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Fireball : MonoBehaviour
{
public GameObject knight;
public GameObject archer;
public GameObject player;
private bool collided;
public void OnCollisionEnter(Collision collision)
{
if(collision.gameObject.tag != "Player" && !collided)
{
collided = true;
Destroy(gameObject);
}
}
}
Spawn Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RandomEnemySpawn : MonoBehaviour
{
public GameObject player;
public GameObject archer;
public GameObject knight;
public bool playerIsDead;
private int xPos1;
private int zPos1;
private int xPos2;
private int zPos2;
void Start()
{
playerIsDead = player.GetComponent<PlayerController>().isDead;
StartCoroutine(spawnEnemy1());
StartCoroutine(spawnEnemy2());
}
IEnumerator spawnEnemy1()
{
while (!playerIsDead)
{
xPos1 = 97;
zPos1 = 67;
Instantiate(archer, new Vector3(xPos1, 0 , zPos1), Quaternion.identity);
Instantiate(knight, new Vector3(xPos1, 0 , zPos1), Quaternion.identity);
yield return new WaitForSeconds(20);
}
}
IEnumerator spawnEnemy2()
{
while (!playerIsDead)
{
xPos1 = 50;
zPos1 = 55;
Instantiate(archer, new Vector3(xPos1, 0, zPos1), Quaternion.identity);
Instantiate(knight, new Vector3(xPos1, 0, zPos1), Quaternion.identity);
yield return new WaitForSeconds(20);
}
}
}
That's all of the script that is needed to play the game. I check all the game objects/scripts that is needed to be assign to each, it's all there
Comment
Your answer
![](https://koobas.hobune.stream/wayback/20220613061509im_/https://answers.unity.com/themes/thub/images/avi.jpg)