Hi all,
So I’m trying to get my player in my game to attack the closest target within a distance when the player isn’t moving. I’m new to programming, and I have mostly been using the Unity Learn site and googling to figure out solutions to the problems that arise. However I can’t seem to figure out how to find the transform positions of multiple “Enemies” within my game. I can get it to work if I initialize my enemy gameobject constantly in the update method, but it only handles one random gameobjects position at a time. So the mechanic of getting the player to attack the closest enemy doesn’t work, the player just attacks whatever gameobjects position was initialized first. How do I go about writing this code so that I can find all the positions of the enemies that spawn within a wave, and make it so my player attacks the closest one? Perhaps store multiple Vector3 variables somehow? Also if you have any suggestions or advice for my code, I’ll happily take any criticism. I know it’s probably sloppy and inefficient.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
using UnityEngine.Assertions.Must;
using UnityEngine.UIElements;
public class PlayerController : MonoBehaviour
{
protected Joystick joystick;
private Animator playerAnim;
private Rigidbody playerRb;
private GameObject[] enemy;
private GameObject firePos;
public GameObject arrowPrefab;
public HealthBar healthBar;
public int maxHealth = 100;
public int currentHealth;
private int enemyCount;
private float movementSpeed = 5.0f;
private float minAttackDistance = 8.0f;
private float rotationSpeed = 0.5f;
private float distance;
private float timer;
private float aimTime = 0.5f;
private float attackDelay = 1.0f;
private float attackTimer = 0f;
private float arrowDelay = 0.2f;
public bool gameOver;
void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
//Gets the fire position game object thats attached to the palyer
firePos = GameObject.Find("FirePos");
//Gets the Enemy Gameobject
enemy = GameObject.FindGameObjectsWithTag("Enemy");
//gets the animator on the player
playerAnim = GetComponentInChildren<Animator>();
//gets the Rigidbody on the player
playerRb = GetComponent<Rigidbody>();
//get the joystick asset from the scene
joystick = FindObjectOfType<Joystick>();
}
void Update()
{
timer += Time.deltaTime;
enemyCount = FindObjectsOfType<EnemyController>().Length;
if (enemyCount == 0)
{
enemy = GameObject.FindGameObjectsWithTag("Enemy");
}
//Code trying to get player to attack enemy within range
distance = Vector3.Distance(transform.position, enemy.transform.position);
//sets the animations to play for the player based on parameters
if (playerRb.velocity.magnitude > 0)
{
playerAnim.SetBool("Walk_b", true);
attackTimer = 0f;
}
else if (playerRb.velocity.magnitude == 0)
{
playerAnim.SetBool("Walk_b", false);
attackTimer += Time.deltaTime;
}
if (playerRb.velocity.magnitude > 3)
{
playerAnim.SetBool("Run_b", true);
}
else if (playerRb.velocity.magnitude < 3)
{
playerAnim.SetBool("Run_b", false);
}
if (currentHealth == 0)
{
playerAnim.SetBool("Death_b", true);
gameOver = true;
Debug.Log("Game Over!");
}
//Rotates the player towards enemy when within distance
if (distance < minAttackDistance)
{
//Rotates the player in the direction of the enemy
GenerateEnemyPos();
Quaternion targetRotation = Quaternion.LookRotation(GenerateEnemyPos() - transform.position);
targetRotation.x = 0;
targetRotation.z = 0;
transform.rotation = Quaternion.Slerp(transform.rotation, targetRotation, rotationSpeed);
}
//Statement that makes the player attack if within range and can attack
if (distance < minAttackDistance && playerRb.velocity.magnitude == 0 && timer >= attackDelay && attackTimer > aimTime)
{
playerAnim.SetBool("Attack_b", true);
InvokeRepeating("Attack", arrowDelay, attackDelay);
}
// gets the rigidbody component from the player
var rigidbody = GetComponent<Rigidbody>();
// adds force to the player in the direction of the joystick so the player moves if the game is not over
if (!gameOver)
{
rigidbody.velocity = new Vector3(joystick.Horizontal * movementSpeed, rigidbody.velocity.y, joystick.Vertical * movementSpeed);
//sets the joystick input for the for the rotation
Vector2 input = new Vector2(joystick.Horizontal, joystick.Vertical);
Vector2 inputDir = input.normalized;
//makes it so the players rotation doesnt snap back to the forward position
if (inputDir != Vector2.zero)
{
//Rotates the player based on the angle of the joystick
transform.eulerAngles = Vector3.up * Mathf.Atan2(inputDir.x, inputDir.y) * Mathf.Rad2Deg;
}
}
else if (gameOver)
{
movementSpeed = 0f;
rigidbody.velocity = new Vector3(movementSpeed, movementSpeed, movementSpeed);
}
}
private void OnCollisionEnter(Collision collision)
{
//When the player comes into contact with an enemy, hurt the player 20HP
if (collision.gameObject.CompareTag("Enemy"))
{
TakeDamage(20);
playerAnim.SetTrigger("Damage_trig");
if (currentHealth < 0)
{
currentHealth = 0;
}
}
}
//Method that decreases the health on the health bar
void TakeDamage(int damage)
{
currentHealth -= damage;
healthBar.SetHealth(currentHealth);
}
private void OnTriggerEnter(Collider collision)
{
//When the player collects a heartpickup heal the player 50HP
if (collision.gameObject.CompareTag("Heart"))
{
HealPlayer(50);
}
}
//Method that increases the health on the health bar
void HealPlayer(int health)
{
currentHealth += health;
healthBar.SetHealth(currentHealth);
if (currentHealth > maxHealth)
{
currentHealth = maxHealth;
}
}
void Attack()
{
timer = 0f;
//spawns arrow to shoot at enemy
Instantiate(arrowPrefab, firePos.transform.position, transform.rotation);
CancelInvoke();
playerAnim.SetBool("Attack_b", false);
}
private Vector3 GenerateEnemyPos()
{
Vector3 enemyPos = enemy.transform.position;
return enemyPos;
}
}
Thanks in advance!