Recoil animation boolean instantly goes to false - c#

So I am trying to make it so that when the user shoots the recoil animation plays, but I have an issue where the bool (which goes true the moment the Fire() is called), instantly goes back to false. I have tried to remove the line of code which is supposed to only make the bool false once the user stopped firing the gun, but the result of that was just the recoil animation playing in a loop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WeaponFire : MonoBehaviour
{
public GameObject playerCam; // The player camera
public float range = 150f;
public float damage = 25f;
public float rounds = 30f;
public float mags = 3f;
public GameObject FPS_char; // The gameobject that has the animator
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (FPS_char.GetComponent<Animator>().GetBool("WeaponFire")) // Check to see if the player has fired
{
FPS_char.GetComponent<Animator>().SetBool("WeaponFire", false); // Set to false if true
}
}
public void Fire()
{
// Shoot a ray
RaycastHit hit;
// Set the WeaponFire bool to true when Fire() is called, which is called when the player presses the left mouse button
FPS_char.GetComponent<Animator>().SetBool("WeaponFire", true);
// Create a ray
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hit, range))
{
if (rounds <= 0)
{
// Player needs to reload
return;
}
if(rounds >= 0)
{
rounds -= 1f;
gameObject.GetComponent<AudioSource>().Play(); // Play a weapon fire sound
EnemyManager enemyManager = hit.transform.GetComponent<EnemyManager>(); // A script that gives the enemies health and attack damage etc
if (enemyManager != null) // check to see if what the player hit contains that script (if it does then it is an enemy)
{
enemyManager.Hit(damage); // Call the Hit() function of the script on the enemy which removes health from the enemy depending on how much damage the weapon does
}
}
}
}
public void Reload()
{
mags -= 1f;
rounds = 30f;
// Add a reload animation
}
}

For things that need to play once use animator.SetTrigger which plays the animation when it is called once automatically. You need to change the Animator parameter from Bool to Trigger in the Animator window.
public void Fire()
{
FPS_char.GetComponent<Animator>().SetTrigger("Fire");
}

Related

How can I make it so that the player loses health when an enemy collides with a different object?

Here an image of what my game looks like so far so that you can get a better idea but I need it so that when one of the outer capsules touches the red box the player (middle capsule) loses health.
I have tried creating a new script which checks for collisions but I couldn't get it to work and am unsure where to go from here. Below is my code for how the health bar works and pressing the space bar reduces health for demonstration purposes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerHealth : MonoBehaviour
{
public float MaxHealth;
public Slider _slide;
private float currentHealth;
void Start()
{
currentHealth = MaxHealth;
_slide.maxValue = MaxHealth;
_slide.value = MaxHealth;
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
void TakeDamage(float Damage)
{
currentHealth = currentHealth - Damage;
_slide.value = currentHealth;
}
}
At one point I tried using
void Update()
{
(collision.collider.name == "Barrier");
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
but realised this is completely wrong, as well as trying to add a box collider to the red "barrier" to aid this but it didn't fix anything.
Update 2:
Also tried changing it so that the enemies move towards the barrier and not the player and added the code:
private void OnTriggerEnter(Collider other) {
TakeDamage(25f);
if(currentHealth <=0)
{
//move to game over
}
}
which doesn't present any errors but rather just doesn't do anything. The enemy capsules just go through it and to the centre, with no health being lost.
You need to check for collisions using OnCollisionEnter3D and then use the TakeDamage function inside of it. Here is an example:
public class PlayerHealth: MonoBehaviour
{
void OnCollisionEnter3D(Collision3D col) //Check for collision
{
TakeDamage(25f);
}
}
Note that for this function to work, both objects need a 3d collider and a rigid body. If you don't want your character to fall, just set gravity to 0.

Player health will not go down

i have tried to make it so whenever the enemy collides with Player1 health drops, i have all of the public floats and transforms setup, but the health in the debug menu shows it just doesnt go down, any ideas?
(attached to player1)
using System.Collections;
using System.Collections;
using UnityEngine;
public class PlayerHealth : MonoBehaviour
{
private float health = 0f;
public Transform player;
[SerializeField] private float maxHealth = 100f;
private void Start() {
health = maxHealth;
}
public void UpdateHealth (float mod) {
health += mod;
if (health > maxHealth){
health = maxHealth;
} else if (health <= 0f){
health = 0f;
Debug.Log("Player Respawn");
}
}
}
attached to enemy:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyAttack : MonoBehaviour
{
[SerializeField] private float attackDamage = 10f;
[SerializeField] private float attackSpeed = 1f;
public Transform player;
private float canAttack;
// Start is called before the first frame update
private void OnCollisionStay2D(Collision2D other) {
if (other.gameObject.tag == "Player1"){
if (attackSpeed <= canAttack){
other.gameObject.GetComponent<PlayerHealth>().UpdateHealth(-attackDamage);
canAttack = 0f;
}else {
canAttack += Time.deltaTime;
}
}
}}
You are serializing the Max Health, not the current health, so the value shown in the inspector will never change. Add the SerializeField to the health value as well and you'll see the current health.
[SerializeField]
private float health = 0f;
Beyond that, it's difficult to see if the code isn't working. I would ensure that the tag you're checking for is actually set on the Player, and add a debug message to OnCollisionStay2D to ensure the collision handler is being called. If it isn't, ensure you have the collider components on both the enemy game object and the player gameobject.
Depending on your intention, you may want to move the canAttack modifier to Update(), since your current logic will only "refresh" the canAttack timer when the enemy is actually colliding with the player. If the enemy hits a player and the player runs away, and comes back ten minutes later and runs into the enemy, the enemy won't attack, they'll only start "healing" their canAttack timer until it's ready again. Maybe this is what you want, but I suspect that it should go into Update() so enemies that have already attacked "rest up" at all times.

Why isn't my program recognizing my target object

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AI;
public class AIController : MonoBehaviour {
[Header("Player interaction")]
[SerializeField] private GameObject target;
[SerializeField] private int damage;
[SerializeField] private float attackDelay;
[SerializeField] private float stunTime;
[SerializeField] private int health;
public int Health{
get{return health; }
set{ health = value;
agent.speed = runningSpeed;
agent.SetDestination(target.transform.position);
onPatrol = false;
if (health <= 0){
Destroy(gameObject);
}
}
}
// Update is called once per frame
void Update () {
CanAttack(target);
}
here i want to make sure that the AI will attack the player only when he is in front of the AI and within .5 meters. the reason i use this instead of OnTriggerEnter is that the AI will only end up attacking once and then just stand on top of the player without really doing anything further
void CanAttack (GameObject other)
{
Vector3 vectorToTarget = other.transform.position - transform.position;
float angleToTarget = Vector3.Angle(transform.forward, vectorToTarget);
if (angleToTarget <= FOV)
{
RaycastHit raycastData;
if (Physics.Raycast(transform.position, vectorToTarget, out raycastData, .5f))
{
GameObject newTarget = raycastData.collider.gameObject;
Attack(target);
}
}
}
I have also used Attack(other) and this still does not work
void Attack(GameObject other)
{
if (!hasAttacked)//if the AI has not recently attacked
{
if (!Player.isShieldOn)//if the player shield is not up
{
if (!Player.hasShieldBraclet)//if the player has the shield braclet
{
other.gameObject.GetComponent<Player>().Health -= damage - ShieldBraclet.dmgReduction;//reduce the amount of damage taken
}
else
{
other.gameObject.GetComponent<Player>().Health -= damage;//otherwise take normal damage
}
StartCoroutine("DelayAttack");//delay time until AI can attack again
}
else
{
StartCoroutine(Stun(stunTime));//if the shield was up stun this enemy
}
}
}
this is used to make sure that the AI waits a moment before attacking again that way the player doesn't die instantly upon touching the AI.
IEnumerator DelayAttack()
{
hasAttacked = true;//the AI has attacked
yield return new WaitForSeconds(attackDelay);//wait to attack again
hasAttacked = false;//the AI can now attack again
}
}
For the most part everything runs fine but when it reaches the code to deal damage to the player it tells me that the object reference is not set to an instance of an object. How can I fix this?
The Specific error code is: NullReferenceException: Object reference not set to an instance of an object Enemy.Attack(UnityEngine.GameObject other).
This is referring to the line
other.gameObject.GetComponent<Player>().Health -= damage - ShieldBraclet.dmgReduction;//reduce the amount of damage taken

Get enemy attack to the fps controller?

using UnityEngine;
using System.Collections;
public class EnemyAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 10; // The amount of health taken away per attack.
Animator anim; // Reference to the animator component.
GameObject player; // Reference to the player GameObject.
PlayerHealth playerHealth; // Reference to the player's health.
//EnemyHealth enemyHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
void Awake ()
{
// Setting up the references.
player = GameObject.FindGameObjectWithTag ("Player");
playerHealth = player.GetComponent <PlayerHealth> ();
//enemyHealth = GetComponent<EnemyHealth>();
anim = GetComponent <Animator> ();
}
public void OnTriggerEnter (Collider other)
{
// If the entering collider is the player...
if(other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
anim = ("idle0ToAttack1");
}
}
void OnTriggerExit (Collider other)
{
// If the exiting collider is the player...
if(other.gameObject == player)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update ()
{
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if(timer >= timeBetweenAttacks && playerInRange /*&& enemyHealth.currentHealth > 0*/)
{
// ... attack.
Attack ();
}
// If the player has zero or less health...
if(playerHealth.currentHealth <= 0)
{
// ... tell the animator the player is dead.
Destroy(this.gameObject);
}
}
void Attack ()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if(playerHealth.currentHealth > 0)
{
// ... damage the player.
playerHealth.TakeDamage (attackDamage);
}
}
}
I want to get the enemy attack to the fps player. How do I do that? At the same time I want my fps controller to die. For your help I've also written the comments so that you all can understand.
I am assuming that you want your enemy to Path Find the player.
Read this if you need more help: Unity Topics: Navigation
First step, all objects that you want for your enemy to walk on must be selected as "static". (Click on the GameObject and tick 'static' in the top right corner)
Now you need to go to Windows>Navigation and click "Bake" down the bottom once you like your settings.
Make sure your "Enemy" has a rigid body on them and then add "Nav Mesh Agent" component.
Now add (or edit) a script on the enemy and add the code (make sure to add this up the top using UnityEngine.AI;):
//NavMeshAgent
private NavMeshAgent agent;
//Target Transform
public Transform trans;
void Start()
{
//Get the component
agent = GetComponent<NavMeshAgent>();
}
private void Update()
{
SetDestination(trans.position);
}
void SetDestination (Vector3 des)
{
//Set the destination
agent.SetDestination(des);
}
And there you go, there are other methods of doing this but this is by far the simplest.
EDIT:
This is what your script should look like:
using UnityEngine;
using System.Collections;
using UnityEngine.AI;
public class EnemyAttack : MonoBehaviour
{
public float timeBetweenAttacks = 0.5f; // The time in seconds between each attack.
public int attackDamage = 10; // The amount of health taken away per attack.
Animator anim; // Reference to the animator component.
GameObject player; // Reference to the player GameObject.
PlayerHealth playerHealth; // Reference to the player's health.
//EnemyHealth enemyHealth; // Reference to this enemy's health.
bool playerInRange; // Whether player is within the trigger collider and can be attacked.
float timer; // Timer for counting up to the next attack.
//NavMeshAgent
private NavMeshAgent agent;
//Target Transform
public Transform trans;
void Start()
{
//Get the component
agent = GetComponent<NavMeshAgent>();
}
void SetDestination(Vector3 des)
{
//Set the destination
agent.SetDestination(des);
}
void Awake()
{
// Setting up the references.
player = GameObject.FindGameObjectWithTag("Player");
playerHealth = player.GetComponent<PlayerHealth>();
//enemyHealth = GetComponent<EnemyHealth>();
anim = GetComponent<Animator>();
}
public void OnTriggerEnter(Collider other)
{
// If the entering collider is the player...
if (other.gameObject == player)
{
// ... the player is in range.
playerInRange = true;
anim = ("idle0ToAttack1");
}
}
void OnTriggerExit(Collider other)
{
// If the exiting collider is the player...
if (other.gameObject == player)
{
// ... the player is no longer in range.
playerInRange = false;
}
}
void Update()
{
SetDestination(trans.position);
// Add the time since Update was last called to the timer.
timer += Time.deltaTime;
// If the timer exceeds the time between attacks, the player is in range and this enemy is alive...
if (timer >= timeBetweenAttacks && playerInRange /*&& enemyHealth.currentHealth > 0*/)
{
// ... attack.
Attack();
}
// If the player has zero or less health...
if (playerHealth.currentHealth <= 0)
{
// ... tell the animator the player is dead.
Destroy(this.gameObject);
}
}
void Attack()
{
// Reset the timer.
timer = 0f;
// If the player has health to lose...
if (playerHealth.currentHealth > 0)
{
// ... damage the player.
playerHealth.TakeDamage(attackDamage);
}
}
}

unity3D, enemy following issue

I'm trying to make enemies follow my player when the player enters the radius area of an enemy, but make the enemy stop following when my bullet hits object or enters radiusArea.
See my gif for more detail:
Gif
script:
using UnityEngine;
using System.Collections;
public class FlyEnemyMove : MonoBehaviour
{
public float moveSpeed;
public float playerRange;
public LayerMask playerLayer;
public bool playerInRange;
PlayerController thePlayer;
// Use this for initialization
void Start()
{
thePlayer = FindObjectOfType<PlayerController>();
}
// Update is called once per frame
void Update()
{
flip();
playerInRange = Physics2D.OverlapCircle(transform.position, playerRange, playerLayer);
if (playerInRange)
{
transform.position = Vector3.MoveTowards(transform.position, thePlayer.transform.position, moveSpeed * Time.deltaTime);
//Debug.Log(transform.position.y);
}
//Debug.Log(playerInRange);
}
void OnDrawGizmosSelected()
{
Gizmos.DrawWireSphere(transform.position, playerRange);
}
void flip()
{
if (thePlayer.transform.position.x < transform.position.x)
{
transform.localScale = new Vector3(0.2377247f, 0.2377247f, 0.2377247f);
}
else
{
transform.localScale = new Vector3(-0.2377247f, 0.2377247f, 0.2377247f);
}
}
}
I hope someone can help me :(
Physics2D.OverlapCircle detects only the collider with the lowest z value (if multiple are in range). So you either need to change the z values so the player has the lowest or you need to work with Physics2D.OverlapCircleAll and check the list to find the player. Or you could change your layers so only the player itself is on that specific layer you feed into the overlap test.

Categories