Im trying to make a system in which my UI will display the nearest enemys health and sprite. I have already got the panels and UI working to display the Player health but im unsure as to how to display whichever enemy has came close or within range of the player.
** The game is running around but coming within range of an enemy triggers combat**
The below code can display a characters health if I place the script on the player/enemy. Im grabbing two variables from Bolt also.
I can display a single enemy no problem in this way. But if i put 50 enemies in one scene it means I have to manually load the panels/UI for each enemy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Bolt;
using Ludiq;
using UnityEngine.UI;
public class HealthAndCombat : MonoBehaviour
{
public GameObject player;
public Slider healthBarSlider;
public float health;
private bool inCombat;
private GameObject nearestEnemy;
public GameObject healthBarCanvas;
public GameObject bestFighterUI;
private void Start()
{
healthBarSlider.value = health;
bestFighterUI.SetActive(false);
}
void Update()
{
health = (float)Variables.Object(player).Get("Health");
inCombat = (bool)Variables.Object(player).Get("combat");
nearestEnemy = (GameObject)Variables.Object(player).Get("nearestEnemy");
if (inCombat)
{
healthBarCanvas.SetActive(true);
bestFighterUI.SetActive(true);
healthBarSlider.value = health;
}
else {
healthBarCanvas.SetActive(false);
bestFighterUI.SetActive(false);
}
}
Im thinking -
-Load the scene.
-Find all objects called enemy and register their health in a list.
-Work out distance from player to each enemy.
-If player in combat, display nearest enemy to player.
I just dont know should I have an overall scene manager for code or have scripts for detection on each player.
Related
I have recently started creating a c# game due to it being a mandatory assignment in my computer science course however i am new to c# and have hit a bump. I have written a Healthbar script so that when my player collides with a gameobject tagged "Enemy" the players health should reduce by 20. However when i press play the health bar visual did not decrease as it should. Like i said i am new to c# so im not too sure how to fix it. I have searched many tutorials however they all gave me the same suggestion of checking to make sure the inspector window of my player and enemy is correct.
After making sure everyting is linked up properly including making the player box collider to " is trigger" and then adding a capsule collider so that it still interacts like a solid object, the code i wrote still didnt work, and whenever i hit my enemy which i tagged as "Enemy" the health bar visual did not change/decrease. I thought that maybe it was just the visual and my health was actually reducing, so to check this i added debugging code to produce a message in the console whether the OnTriggerEnter code was working properly and to my surprise it did not work. I added multiple other debugging code lines as well and none of them showed that anything was working.
This is my player script, giving my player health and allowing the TakeDamage code to run if i enter the enemies collider.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
public int maxHealth = 100;
public int currentHealth;
public HealthBar healthBar;
// Start is called before the first frame update
void Start()
{
currentHealth = maxHealth;
if (healthBar != null)
{
healthBar.SetMaxHealth(maxHealth);
}
}
// Update is called once per frame
void Update()
{
}
void TakeDamage(int damage)
{
currentHealth -= damage;
if (currentHealth < 0)
{
// Trigger game over event
Debug.Log("Game over!");
}
healthBar.SetHealth(currentHealth);
}
// This function is called when the player collides with an enemy
void OnTriggerEnter(Collider other)
{
Debug.Log("Collision detected!");
if (other.gameObject.tag == "Enemy")
{
// Decrease the player's health by a certain amount
TakeDamage(20);
}
}
}
And this is my healthbar script which should update and decrease based on the value after the TakeDamage line is executed upon collding with the enemy, however no matter what i try, it doesnt seem to update, nor do any debug areas appear in my console, showing that the script isnt detecting the collision between me and my enemy.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HealthBar : MonoBehaviour
{
public Slider slider;
public Gradient gradient;
public Image fill;
public void SetMaxHealth(int health)
{
slider.maxValue = health;
slider.value = health;
fill.color = gradient.Evaluate(1f);
}
public void SetHealth(int health)
{
slider.value = health;
fill.color = gradient.Evaluate(slider.normalizedValue);
}
}
I am trying to build a flappy bird like game and I am trying to spawn enemy birds and gold coins so I have written the C# code and the made the prefabs, but when I run the bird and the coins are not respawning.
This is the respawn code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnPlayer : MonoBehaviour
{
public GameObject GameObjectToSpawn;
private GameObject Clone;
public float timeToSpawn = 4f;
public float FirstSpawn = 10f;
// Update is called once per frame
void Update()
{
FirstSpawn -= Time.deltaTime;
if (FirstSpawn <= 0f)
{
Clone = Instantiate(GameObjectToSpawn, gameObject.transform.localPosition, Quaternion.identity) as GameObject;
FirstSpawn = timeToSpawn;
}
}
}
screenshot of unity:
This where i am respawning the first enemy bird:
From your second screenshot it seems to be spawned but way off the screen! You can still see the tiny little island in the bottom left corner.
You thought seems to be that you have to spawn it in the Canvas pixel space using the spawn point's localPosition. But this is not the case since Instantiate places it into the scene root (without any parent) with absolute world-space position into the scene.
You should rather actually place the spawn point to the absolute world position where the spawn should happen and rather use
Clone = Instantiate(GameObjectToSpawn, transform.position, Quaternion.identity);
Btw no need for the as GameObject since Instantiate already returns the type of the given prefab.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveProjectile : MonoBehaviour
{
public Rigidbody2D projectile;
public float moveSpeed = 10.0f;
// Start is called before the first frame update
void Start()
{
projectile = this.gameObject.GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void Update()
{
projectile.velocity = new Vector2(0,1) * moveSpeed;
}
void OnCollisionEnter2D(Collision2D col){
if(col.gameObject.name == "Enemy"){
gameObject.name == "EnemyHeart5".SetActive(false);
}
if(col.gameObject.name == "Top"){
DestroyObject (this.gameObject);
}
}
}
This is the code to my player projectile. On collision i tried to reference it to a game object i have called playerheart and it doesnt seem to work out the way i wanted it to.
Im trying to make a health system where if my bullet collides with the enemy game object the health would decrease by one. Im pretty new to Unity and im confused on how to target the hearts when the bullets collide.
I'm assuming "EnemyHeart5" is a GameObject inside Enemy as child gameobject. Correct?
Issue here is when the collision takes place, it recognize "Enemy" gameobject and won't have access to "EnemyHeart5" for disabling it. I'd suggest you to add simple EnemyManager script into your enemy which manages your enemy health and health related gameobject (ie. EnemyHearts which you are displaying). When collision takes place, access that EnemyManager component and change health value.
void OnCollisionEnter2D(Collision2D col){
if(col.gameObject.tag == "Enemy"){
col.gameObject.GetComponent<EnemyManager>().health =-1;
}
Now, in the update method of EnemyManager you check the health value and disable EnemyHealth5 component.
Also, use "tag" in collision instead of "name". name will create issues when you have multiple enemies in the game. Make sure you add tag in enemy gameobject if you are using it.
Hope this helps, let me know how it goes.
I am trying to make a zombie wave game and current have a Prefab for my enemies. If I have the prefab be in the scene when I hit run, they are attached to the NavMesh and track the player perfectly. I want to achieve this but with the enemy being spawned from an empty GameObject so I can get the waves spawning in. I have achieved them Spawning but they have the error,
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:SetDestination(Vector3)
EnemyAI:Update() (at Assets/Scripts/EnemyAI.cs:25)
Here is my EnemyAI Script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class EnemyAI : MonoBehaviour
{
public float lookRadius = 10f;
Transform target;
NavMeshAgent agent;
public GameObject Player;
void Start()
{
agent = GetComponent<NavMeshAgent>();
}
// Update is called once per frame
void Update()
{
float distance = Vector3.Distance(Player.transform.position, transform.position);
if (distance <= lookRadius)
{
agent.SetDestination(Player.transform.position);
}
}
}
And my spawning script, which is attached to an empty game object,
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Spawning : MonoBehaviour
{
public GameObject prefab;
public int CountofCubes;
private IEnumerator coroutine;
public float spawnRate;
IEnumerator Start()
{
while (true)
{
for (int i = 0; i < CountofCubes; i++)
{
Instantiate(prefab, new Vector3(Random.Range(-25.0f, 25.0f), 0.5f, Random.Range(-25.0f, 25.0f)), Quaternion.identity);
}
yield return new WaitForSeconds(spawnRate);
}
}
}
Any help would be great thanks!
I had the same issue and I don't have an explanation but only a workaround:
In the Start fucntion, I added:
navAgent = GetComponent<NavMeshAgent>();
navAgent.enabled = false;
// Invoke is used as a workaround for enabling NavMeshAgent on NavMeshSurface
Invoke("EnableNavMeshAgent", 0.025f);
And the EnableNavMeshAgent function is just :
private void EnableNavMeshAgent ()
{
navAgent.enabled = true;
}
If I set the invoke delay to a value less than 0.025 second the error keep going but for 0.025 I only have it twice and the behaviour is the one I wanted after that.
Some reasons this might happen:
The agent is not on level with any navmesh i.e. can be too far above or below. You want it to be "close to the NavMesh surface". Use raycasting on the floor to position the agent or add a rigidbody and drop it from above the floor. After you do this you might need to disable and enable the agent.
Moving the transform yourself rather than using Wrap function. There's property where you can check if the simulated and actual position are in sync.
Corrupted navmesh so you might need to re-bake it.
It is essentially trying to tell you your agent is not on the mesh so it cannot find a path. Try playing with where you're placing the agent.
I kind of remember running into a similar problem a while back and problem was I forgot to bake the NavMesh in Window > AI > Navigation. Just in case.
Screenshot of the bullets when firing :
The bullets are stay still and they are standing.
This screenshot show the Fire Point inspector position rotation scaling :
And a screenshot of the bullet prefab settings :
Last screenshot show the Shooting gameobject inspector settings :
And the script Shooting :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Shooting : MonoBehaviour
{
[SerializeField]
private Transform[] firePoints;
[SerializeField]
private Rigidbody projectilePrefab;
[SerializeField]
private float launchForce = 700f;
public void Update()
{
if (Input.GetButtonDown("Fire1"))
{
LaunchProjectile();
}
}
private void LaunchProjectile()
{
foreach (var firePoint in firePoints)
{
var projectileInstance = Instantiate(
projectilePrefab,
firePoint.position,
firePoint.rotation);
projectileInstance.AddForce(firePoint.forward * launchForce);
}
}
}
And how can I make that it will not leave a trail of bullets behind ?
For the rotation you want to set the projectile to the same rotation as the weapon.
transform.rotation = Quaternion.Euler(gunAngle)
the projectile should be another gameObject instead of rigidBody.
you'll also need a destruction script on them or they'll never disappear and you will have a million projectiles in play lagging the game. destroy gameObject by collision and time.
Regarding the trail of bullets, you should consider adding a cooldown to the LaunchProjectile method. Right now every time update is called it calls LaunchProjectile if the fire button is down, even if it called LaunchProjectile the update before (at 60 ups(?) you'd have to be pretty fast off of the fire button to only shoot one projectile).