Unity Inputs Keeps Pressed - c#

This is my shooting script, I set these in fixed update method, as it should be, but my mouse inputs keeps pressed, I am trying to make an fps game but my mouse input keeps pressed, anyone can help me? This also happens in keyboard inputs.
void FixedUpdate()
{
if(isReloading)
{
return;
}
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
if(Input.GetKey(KeyCode.R))
{
Debug.Log("R key was pressed.");
StartCoroutine(Reload());
return;
}
if(Input.GetButton("Fire1") && Time.time >= nextTimeToFire)
{
nextTimeToFire = Time.time + 1f / fireRate;
Shooting();
}
}
IEnumerator Reload()
{
isReloading = true;
UIController.instance.reloadMSG.gameObject.SetActive(true);
Debug.Log("reloading");
yield return new WaitForSeconds(reloadTime);
currentAmmo = maxAmmo;
isReloading = false;
UIController.instance.reloadMSG.gameObject.SetActive(false);
}
private void Shooting()
{
currentAmmo--;
Debug.Log("Current Ammo:" + currentAmmo);
RaycastHit hit;
if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
{
GameObject bulletImpactObject = Instantiate(bulletImpact, hit.point + (hit.normal * 0.002f), Quaternion.LookRotation(hit.normal, Vector3.up));
Destroy(bulletImpactObject, 10f);
}
UIController.instance.ammoTXT.text = (currentAmmo + " / " + maxAmmo).ToString();
}

A few years ago I did a top-down shooter, and I had a similar problem. Try changing this:
if(Input.GetButton("Fire1") && Time.time > nextTimeToFire)
{
nextTimeToFire = Time.time + fireRate;
Shooting();
}
Removing the '=' from the comparison, and just adding the fire rate instead of dividing. That's how I did back then.
Also, are you planning to do something while the gun is reloading? Because if not and it's just checking if it's reloading, you can just do this:
if !(isReloading)
{
if (currentAmmo <= 0)
{
StartCoroutine(Reload());
return;
}
if(Input.GetKey(KeyCode.R))
{
Debug.Log("R key was pressed.");
StartCoroutine(Reload());
return;
}
if(Input.GetButton("Fire1") && Time.time > nextTimeToFire)
{
nextTimeToFire = Time.time + fireRate;
Shooting();
}
}

Here is GunController script that does what you want. Added is a weapon recoil
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GunController : MonoBehaviour
{
public GameObject bulletPrefab; // Prefab of the bullet
public Transform bulletSpawn; // Spawn point for the bullet
public float fireRate = 0.5f; // Rate of fire in seconds
public float recoil = 10f; // Recoil force applied to the player
public int magazineSize = 6; // Size of the magazine
public float reloadTime = 1.5f; // Time it takes to reload the gun
private int currentAmmo; // Current ammo in the magazine
private bool isReloading; // Flag to check if the gun is being reloaded
private float nextFire = 0.0f; // Time when the player can fire again
void Start()
{
// Initialize the current ammo to the size of the magazine
currentAmmo = magazineSize;
}
void Update()
{
// Check if the player has pressed the fire button and if it's time to fire again
if (Input.GetButton("Fire1") && Time.time > nextFire && !isReloading && currentAmmo > 0)
{
// Set the time when the player can fire again
nextFire = Time.time + fireRate;
// Create a bullet at the spawn point
var bullet = (GameObject)Instantiate(bulletPrefab, bulletSpawn.position, bulletSpawn.rotation);
// Add force to the bullet
bullet.GetComponent<Rigidbody>().AddForce(bullet.transform.forward * 500);
// Apply recoil force to the player
GetComponent<Rigidbody>().AddForce(-transform.forward * recoil, ForceMode.Impulse);
// Decrement the current ammo
currentAmmo--;
}
// Check if the player has pressed the reload button and if the gun is not being reloaded
if (Input.GetKeyDown(KeyCode.R) && !isReloading)
{
// Set the reload flag to true
isReloading = true;
// Start the reload coroutine
StartCoroutine(Reload());
}
}
IEnumerator Reload()
{
// Wait for the reload time
yield return new WaitForSeconds(reloadTime);
// Set the current ammo to the size of the magazine
currentAmmo = magazineSize;
// Set the reload flag to false
isReloading = false;
}
}
This script should be attached to the game object that represents the gun. The script has several public variables that you can customize:
bulletPrefab is the prefab of the bullet that will be fired.
bulletSpawn is the transform component of the game object that represents the spawn point for the bullet.
fireRate is the rate of fire in seconds. This determines how often the gun can be fired.
recoil is the recoil force applied to the player when the gun is fired.
magazineSize is the size of the magazine. This determines how many bullets the gun can hold.

Related

AI wandering state doesn't seem to work right

I've been trying to make an AI system that would follow specific waypoints and once the player character walks into the trigger zone, the AI would start chasing the character and vice versa.
It seems that this does kind of work, but the AI only moves to one waypoint and then stops until the player walks into the trigger zone; after which if the player walks out, it again only goes to one waypoint then stops again.
I have multiple waypoints and I just want it to keep cycling through them, but it just goes to one of them and stops.
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
using UnityEngineInternal;
public class AILocomotion : MonoBehaviour
{
public Transform playerTransform;
NavMeshAgent agent;
Animator animator;
public float maxTime = 1.0f;
public float maxDistance = 1.0f;
float timer = 0.0f;
bool moveTowards = false;
bool followWaypoint = false;
float deaccel= 0.5f;
float calVelocity = 0.0f;
public Transform[] points;
private int destPoint = 0;
public string animState;
void Start()
{
agent = GetComponent<NavMeshAgent>();
animator = GetComponent<Animator>();
moveTowards = false;
followWaypoint = true;
}
// Update is called once per frame
void Update()
{
if (moveTowards == true)
{
timer -= Time.deltaTime;
if (timer < 0.0f)
{
float sqDistance = (playerTransform.position - agent.destination).sqrMagnitude;
if (sqDistance > maxDistance * maxDistance)
{
agent.destination = playerTransform.position;
}
}
animator.SetFloat("Speed", agent.velocity.magnitude);
}
else if (!moveTowards && agent.velocity.magnitude>0.0f)
{
calVelocity = agent.velocity.magnitude;
calVelocity -= Time.deltaTime * deaccel;
animator.SetFloat("Speed", calVelocity);
}
//CHECKS IF BOTH CONDITIONS HAVE MET AND RUNS THE WAYPOINT FOLLOWING CODE
if (followWaypoint == true && (!agent.pathPending && agent.remainingDistance < 1.0f))
{
GotoNextPoint();
}
Debug.LogError("Bool" + followWaypoint);
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
moveTowards = true;
//DISABLES THE WAYPOINT FOLLOWING CODE TO RUN THE CHASE CODE INSTEAD
followWaypoint = false;
}
}
private void OnTriggerExit(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
moveTowards = false;
//RE-ENABLES THE WAYPOINT FOLLOWING CODE ONCE THE PLAYER LEAVES THE TRIGGER AREA
followWaypoint = true;
}
}
//THIS IS THE WAYPOINT FOLLOWING CODE
void GotoNextPoint()
{
animator.SetFloat("Speed", agent.velocity.magnitude);
// Returns if no points have been set up
if (points.Length == 0)
return;
// Set the agent to go to the currently selected destination.
agent.destination = points[destPoint].position;
Debug.LogError("DestPoint = " + destPoint);
// Choose the next point in the array as the destination.
// cycling to the start if necessary.
destPoint = Random.Range(0, points.Length);
}
}
Use OnTriggerStay instead of OntriggerEnter and Try

MissingReferenceException Error Occurs with Unity's New Input System when using "buttonEast / rightButton"

I'm getting this error in Unity after pressing the relative "eastButton":
Error: MissingReferenceException while executing 'canceled' callbacks of 'Gameplay/Block[/DualShock4GamepadHID/buttonEast,/Mouse/rightButton]'
UnityEngine.InputSystem.InputActionAsset:OnDestroy () (at Library/PackageCache/com.unity.inputsystem#1.0.2/InputSystem/Actions/InputActionAsset.cs:794)
I'm attempting to set up 'block' functionality within my game which simply locks the player's movement then disables my "canBeHit" bool which will then put the player in a state where they cannot be hit, however upon interacting with the eastButton all player movement is completely locked preventing you from moving, however rotation is still possible. Another part I'd like to note is that I'm working with the Mirror package so I can network my game, unsure if this could also be causing problems. Would really appreciate if someone could point out where I've gone wrong, I'd be very grateful.
PlayerMovementTest.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using Mirror;
public class PlayerMovementTest : NetworkBehaviour
{
[Header ("Default")]
Rigidbody rb;
PlayerInput playerInput;
PlayerControls playerInputActions;
public bool isStunned;
public float stunLockTimer;
public float stunLockTimerEnd;
public Animator animations;
public ParticleSystem stunParticle;
[Header("Movement")]
public float speed;
public float baseSpeed;
[Header ("Dodge")]
public float dodgeMultiplier;
public float dodgeTimer;
public float dodgeTimerMax;
public int dodgeCheck;
public float howLongDodgeLast;
public bool isDodging;
public GameObject enemyPlayer;
public GameObject dodgeParticle;
[Header("Attack")]
public int attackReset;
public float attackTimer;
public float attackTimerResetMax;
public float attackPlayingTimerEnd;
public float lungeAttackLungeMultiplier;
public bool isAttacking;
public GameObject attackParticle;
public GameObject attackHitboxObject;
public GameObject lungeAttackHitboxObject;
[Header("Block")]
public bool canBeHit;
private void Awake()
{
playerInput = GetComponent<PlayerInput>();
rb = GetComponent<Rigidbody>();
playerInputActions = new PlayerControls();
// freezes rotation
rb.freezeRotation = true;
// enables the input controller
playerInputActions.Gameplay.Enable();
playerInputActions.Gameplay.Attack.performed += Attack;
playerInputActions.Gameplay.Attack.canceled += Attack;
playerInputActions.Gameplay.Dodge.performed += Dodge;
playerInputActions.Gameplay.Block.canceled += Block;
playerInputActions.Gameplay.Block.performed += Block;
isStunned = false;
}
public void Update()
{
if (!isLocalPlayer)
return;
// dodge timers and reset
if (dodgeCheck != 1)
dodgeTimer += Time.deltaTime;
if (dodgeTimer > dodgeTimerMax)
{
dodgeCheck += 1;
dodgeTimer = 0;
}
// turns on the slide particle when sliding
if (isDodging == true)
dodgeParticle.SetActive(enabled);
else
dodgeParticle.SetActive(false);
// sets how long the EFFECT of the dash lasts for
// not how long the player will move but how long
// they will be able to collide with another player
// and stun them
if (dodgeTimer > howLongDodgeLast)
isDodging = false;
// attack timers and reset
if (attackReset != 1)
{
attackTimer += Time.deltaTime;
}
// after a certian amount of time the player attack goes away
if (attackTimer > attackPlayingTimerEnd)
{
//attackParticle.SetActive(false);
attackHitboxObject.SetActive(false);
lungeAttackHitboxObject.SetActive(false);
}
if (attackTimer > attackTimerResetMax)
{
attackReset += 1;
attackTimer = 0;
}
// makes it so attacks dont go into the minuses
if (attackReset < 0)
attackReset = 0;
// when player gets stunned it starts a timer where they cannot do any moves
if (isStunned == true)
{
stunLockTimer += Time.deltaTime;
if (stunLockTimer > stunLockTimerEnd)
{
isStunned = false;
stunLockTimer = 0f;
speed = baseSpeed;
}
}
// chanegs between animations depending on how fast the player is moving
if (rb.velocity.magnitude > 4f)
animations.SetFloat("Walk", rb.velocity.magnitude);
if (rb.velocity.magnitude < 4f)
animations.SetFloat("Idle", rb.velocity.magnitude);
// if player is stunned then play stun particle
if (isStunned == true)
stunParticle.Play();
else
stunParticle.Stop();
//edited out the print as it got distracting
// print(rb.velocity.magnitude);
}
// for dodge stun
public void OnCollisionEnter(Collision col)
{
// if you hit a player
if( col.gameObject.tag == "Player")
{
// and in dodge, number picked just as an idea of how long the dash could last
if (dodgeTimer > .1f && dodgeTimer < 1f)
{
// sets the player hit as a gameobject that cabn be affected in script
enemyPlayer = col.gameObject;
// decreases speed (or in this case increases as i cannot test 2 players
enemyPlayer.GetComponent<PlayerMovementTest>().speed = 0;
enemyPlayer.GetComponent<PlayerMovementTest>().isStunned = true;
}
}
}
public void FixedUpdate()
{
// calls movement function
Movement();
}
public void Attack(InputAction.CallbackContext context)
{
if (attackReset == 1 && isStunned == false)
{
isAttacking = true;
attackHitboxObject.SetActive(enabled);
attackReset -= 1;
animations.SetTrigger("Attack");
attackParticle.SetActive(enabled);
}
//if (attackReset == 1 && isStunned == false)
/*
if (context.performed)
{
print("attack start");
}
if (context.canceled)
{
// for luneg attack
rb.AddForce(transform.forward * lungeAttackLungeMultiplier, ForceMode.Impulse);
isAttacking = true;
lungeAttackHitboxObject.SetActive(enabled);
attackReset -= 1;
// animations.SetTrigger("Attack");
// attackParticle.SetActive(enabled);
print("attack end");
}*/
}
public void Dodge(InputAction.CallbackContext context)
{
// checks if the player has a dodge
if (dodgeCheck == 1 && isStunned == false)
{
// used for lockign slide in place and particle effect
isDodging = true;
// adds a force to the player, spped can be adjusted with dodgeMultiplier
rb.AddForce(transform.forward * dodgeMultiplier, ForceMode.Impulse);
// removes dodge
dodgeCheck -= 1;
animations.SetTrigger("Slide");
}
}
public void Block(InputAction.CallbackContext context)
{
if (isStunned == false)
{ // when you hold the button, you lose your speed
if (context.performed)
{
canBeHit = false;
speed = 3;
animations.SetBool("Block", true);
}
// when you release it your speed goes back to normal
if (context.canceled)
{
canBeHit = true;
speed = 15;
animations.SetBool("Block", false);
}
}
}
public void Movement()
{
// used for locking slide in place, no rotation
if (isDodging == false)
{
//player movement, can only use vector2 for controller so we use a vector3
// but store the x and z in a vector 2
Vector2 inputVector = playerInputActions.Gameplay.Walk.ReadValue<Vector2>();
Vector3 tempVec = new Vector3(inputVector.x, 0, inputVector.y);
// adds force to the vector, do this seperately so we can use
//the variable for the player rotation
rb.AddForce(tempVec * speed, ForceMode.Force);
if (tempVec != Vector3.zero)
{
// finds the direction the player is moving
Quaternion targetRotation = Quaternion.LookRotation(tempVec);
// rotates players towards the way they are facing
targetRotation = Quaternion.RotateTowards(transform.rotation, targetRotation, 360 * Time.fixedDeltaTime);
rb.MoveRotation(targetRotation);
}
}
}
}
If any additional information is needed to solve my problem I'm more than happy to submit any necessary info.

Unity: Animation looping while waiting for state transition

I previously posted this question on the gameDev SE but with no luck, therefore I am trying to see if I could find some help here.
I am having some troubles with the transitions in my animator. Specifically, I am trying to set up a some code to handle combo sequences, and to do so I am using coroutines that exploit the state machine given by the animations in the animator. Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
using UnityEngine.SceneManagement;
/*enum PlayerState is a list of states that can be taken by the player character. They will be used to implement a finite state machine-like
behavior with the actions it can take*/
public enum PlayerState {
walk,
attack,
interact,
dash,
stagger
}
public class Player_Base : MonoBehaviour {
//Basic parameters
Rigidbody2D myRigidBody; //These are to call the components of the Player GameObject
public static Transform playerPos;
public PlayerState currentState;
Animator myAnimator;
public HealthManager myStatus;
private bool isAlive = true;
//Sorting layers parameters
public CapsuleCollider2D myFeet;
public static float playerVertPos; // Need this to sort other objects layers in another script.
//Movement parameters
[SerializeField] float moveSpeed = 3f; // use [serfiel] or public in order to have something that you can modify from Unity UI
public Vector2 moveInput;
private bool isMoving;//Implementing the state machine and the *blend trees*, you need only to define one bool for all animations of a kind (eg walking anims)
//Combat parameters
private int comboCounter = 0;
private float comboTimer = 0;
//dash parameters
[SerializeField] float dashTimeMax = 1f;
[SerializeField] float dashTime = 0;
[SerializeField] float dashPush = 0.001f;
[SerializeField] float dashSpeed = 10f;
// Use this for initialization
void Start()
{
currentState = PlayerState.walk;//Initial default state of the player
myRigidBody = GetComponent<Rigidbody2D>(); /*the getcomp looks for the related component in the <> and uses it in the code*/
myFeet = GetComponent<CapsuleCollider2D>();
myAnimator = GetComponent<Animator>();
myAnimator.SetFloat("MoveX", 0);//If i do not set a default values for these, if player attacks without moving first, all colliders will activate and will hit all around him
myAnimator.SetFloat("MoveY", -1);
myStatus = GameObject.FindObjectOfType<HealthManager>();
}
// Update is called once per frame
void Update()
{
playerVertPos = myFeet.bounds.center.y;
moveInput = Vector2.zero;/*getaxis and getaxisraw register the input of the axes and outputs +1 or -1 according to the axis direction*/
moveInput.x = Input.GetAxisRaw("Horizontal");
moveInput.y = Input.GetAxisRaw("Vertical");
if (!isAlive)
{
return;
}
else {
if (currentState == PlayerState.walk)//It will consider walking only when in that state, this means that if it is attacking for instance,
//it needs to change its state. Good for compartimentalization of the actions (otherwise I could have changed the direction of the attacks)
{
if (moveInput != Vector2.zero)//This if statement is such that if there is no new input to update the movement with, the last (idle) animation
//will remain, so if you go right and stop, the player keeps facing right
{
Move();
myAnimator.SetFloat("MoveX", moveInput.x);
myAnimator.SetFloat("MoveY", moveInput.y);
myAnimator.SetBool("isMoving", true);
}
else {
myAnimator.SetBool("isMoving", false);
}
}
//Attack inputs
if (Input.GetKeyDown(KeyCode.Mouse0) && currentState != PlayerState.attack)//second clause because i do not want to indefinitely attack every frame
{
StartCoroutine(FirstAttack());
}
if (Input.GetKeyDown(KeyCode.Space) && currentState != PlayerState.dash)
{
StartCoroutine(Dashing());
}
DeathCheck();//check if player is still alive
}
}
public void Move()
{
moveInput.Normalize();
myRigidBody.MovePosition(myRigidBody.position + moveInput * moveSpeed * Time.deltaTime);
//If i want to work with the velocity vector: i have to use rb.velocity, not just taking the xplatinput times movespeed
}
public void MoveOnAnimation(int xMove, int yMove, float displacement)
{
moveInput.x = xMove;
moveInput.y = yMove;
moveInput.Normalize();
myRigidBody.MovePosition(myRigidBody.position + moveInput * displacement * Time.deltaTime);
}
private IEnumerator FirstAttack() {
//Start Attack
comboCounter = 1;
myAnimator.SetInteger("comboSequence", comboCounter);
currentState = PlayerState.attack;
yield return new WaitForSeconds(AttackTemplate.SetDuration(0.6f) - comboTimer);//Problem: if i reduce the time below the animation time of the second animation, the second animation won't go untile the end
comboTimer = AttackTemplate.SetComboTimer(0.4f);
//if combo not triggered:
while (comboTimer >= 0)
{
Debug.Log(comboTimer);
comboTimer -= Time.deltaTime;
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Debug.Log("Chained");
StopCoroutine(FirstAttack());
StartCoroutine(SecondAttack());
}
yield return null;
}
comboCounter = 0;
myAnimator.SetInteger("comboSequence", comboCounter);
currentState = PlayerState.walk;
}
private IEnumerator SecondAttack()
{
comboCounter = 2;
myAnimator.SetInteger("comboSequence", comboCounter);
currentState = PlayerState.attack;
yield return null;
//if combo not triggered:
yield return new WaitForSeconds(AttackTemplate.SetDuration(0.9f));
comboCounter = 0;
myAnimator.SetInteger("comboSequence", comboCounter);
currentState = PlayerState.walk;
}
private void Dash()
{
if (dashTime >= dashTimeMax)
{
dashTime = 0;
myRigidBody.velocity = Vector2.zero;
currentState = PlayerState.walk;
}
else
{
currentState = PlayerState.dash;
dashTime += Time.deltaTime;
moveInput.Normalize();
Vector2 lastDirection = moveInput;
myRigidBody.velocity = lastDirection * dashSpeed;
}
}
private IEnumerator Dashing()
{
currentState = PlayerState.dash;
for (float timeLapse = 0; timeLapse < dashTime; timeLapse = timeLapse + Time.fixedDeltaTime)
{
moveInput.Normalize();
Vector2 lastDirection = moveInput;
myRigidBody.velocity = lastDirection * dashSpeed;
}
yield return null;
myRigidBody.velocity = Vector2.zero;
currentState = PlayerState.walk;
}
private void DeathCheck() //if the player health reaches 0 it will run
{
if (HealthManager.health == 0) {
isAlive = false; // this is checked in the update, when false disables player inputs
myRigidBody.constraints = RigidbodyConstraints2D.FreezePosition; // if i don't lock its position, the last bounce with the enemy pushes the player towards inifinity
myAnimator.SetTrigger("death");//triggers the death animation
StartCoroutine(LoadNextScene());
}
}
[SerializeField] float LevelLoadDelay = 5f;
[SerializeField] float LevelSlowMo = 1f;
IEnumerator LoadNextScene()
{
Time.timeScale = LevelSlowMo;
yield return new WaitForSecondsRealtime(LevelLoadDelay);
Time.timeScale = 1f;
var CurrentSceneIndex = SceneManager.GetActiveScene().buildIndex;
SceneManager.LoadScene(CurrentSceneIndex + 1);
}
}
What I am doing basically is to use enums to define the player states and on input, if the player is not already in the attacking state, perform an attack. Once the FirstAttack() is called, it will first of all update an integer, comboCounter, which handles the transitions between consecutive attacks, input said integer in the animator and then change my state to attack. After this, I created a while loop that goes on until the end of an established time interval during which the player would be able to press the same attack button to chain the combo. If this does not happen, the state and integer parameter are reset.
The problem I am facing is that while the player can actually perform the combo with the second attack, during all the interval in which the first animation is active it keeps looping. Furthermore, I noticed that the second animation does not reach the end, it seems like it stops once the interval that I previously set will end.
Update: This is the screenshot of my animator window:
The transitions any state -> 1stAttack and 1stAttack -> 2ndAttack is handled by the same integer parameter, comboSequence, which is set to 0 normally, to 1 for 1stAttack and to 2 for the second one. I observed that the transition any state -> 1stAttack is triggered multiple times whenever I press the hit button, in line with the looping problem I am facing.
I have tried a couple of things, for instance using normal functions instead of a coroutine, but in this way, I do not understand why, there are problems with the enums states, also I think that in the long term this approach would be more modular and customisable. I feel like I am missing something trivial but I do not understand what and it has been some time now, so any help would be much appreciated!
Disable Can Transition To Self = false

My bullet spawns randomly and does no damage

using UnityEngine;
using System.Collections;
using System;
public class TurretScript : MonoBehaviour
{
public float rangeToPlayer;
public GameObject bullet;
// public GameObject spherePrefab;
private GameObject player; // Tag for DynamicWaypointSeek
private bool firing = false; //Firing status
private float fireTime; // Fire Time
private float coolDown = 1.00F; // Time to cool down fire
private int health = 5; //Health of turret
private bool bDead;
private Action cur;
void Start()
{
player = GameObject.FindWithTag("Player");
bDead = false;
}
void Update()
{
if (PlayerInRange())
{ // PlayerInRange is bool function defined at the end
transform.LookAt(player.transform.position); //Rotates the transform (weapon) so the forward vector points at /target (Player)/'s current position
RaycastHit hit;
if (Physics.SphereCast(transform.position, 0.5F, transform.TransformDirection(Vector3.forward), out hit))
{ //The center of the sphere at the start of the sweep,The radius of the sphere,The direction into which to sweep the sphere.
if (hit.transform.gameObject.tag == "Player")
{ //information in hit (only interested in "Player")
if (firing == false)
{
firing = true;
fireTime = Time.time; //keep the current time
GameObject bul;
Quaternion leadRot = Quaternion.LookRotation(player.transform.position); //Calculate the angular direction of "Player";
bul = Instantiate(bullet, transform.position, leadRot) as GameObject; // existing object to be copied, Position of Copy, Orientation of Copy
//Destroy(bullet, 2.0f);
}
}
}
}
if (firing && fireTime + coolDown <= Time.time) // prvious time stored in fireTime + cool down time is less --> means the firing must be turn off
firing = false;
// Destroy(GameObject.FindGameObjectWithTag("Bullet"));
if (health <= 0)
cur = Deadstate;
}
protected void Deadstate()
{
if (!bDead)
{
bDead = true;
Explode();
}
}
void Explode()
{
Destroy(gameObject, 1.5f);
}
bool PlayerInRange()
{
return (Vector3.Distance(player.transform.position, transform.position) <= rangeToPlayer); //Vector3.Distance(a,b) is the same as (a-b).magnitude.
}
void OnTriggerEnter(Collider col)
{
HealthBarScript.health -= 10f;
}
}`
This is code I wrote for a enemy turret in my current unity project. The idea is that it will fire a bullet at the player once it's in range and stop when it's out of range and when the bullet collides with the player, the player will take damage, but I'm struggling to figure out why the bullet won't do any damage. Thoughts? Very much appreciate the help!
According to my experience: bullet speed may be too fast to detect collision.
Imagine that in 2d:
frame 1:
.BB.......OOO......
frame 2:
........BBOOO......
frame 3:
..........OOO..BB..
Where OOO is your object and BB is your bullet.
To fix this you can have a bigger collider for the bullet. Other workaround like "dynamic" collider are also possible.

How do i make update function run every frame after I use OnTriggerEnter2D function in Unity?

So i am designing a game where once the object collides with the powerup it should wait for 10 seconds and go back to normal. I am using update function to keep count but once OnTriggerEnter function is used the update function stops running every frame. How do i counter it. Please help
public class Powerup_1act : MonoBehaviour {
//This powerup temporarily passes through all lasers
public GameObject EffectiveTo;
private float TimeRemaining;
int flag=0;
float timer=0.0f;
public float alphalevel=.20f;
public GameObject laserfield;
float flag2=0f;
float countdown=0;
void OnTriggerEnter2D(Collider2D other)
{
//Check the provided Collider2D parameter other to see if it is tagged "PickUp", if it is...
if (other.gameObject.CompareTag("Player"))
{
gameObject.SetActive(false);
laserfield.gameObject.tag = "Temp";
flag2 = 1;
changealpha ();
Debug.Log ("Active?"+gameObject.activeInHierarchy);
StartCoroutine(Powerup());
}
}
private IEnumerator Powerup()
{
countdown = 10f;
while (countdown >= 0) {
Debug.Log (timer);
timer += Time.deltaTime;
if (flag2 == 1) {
//changes the alpha level between 0.2f and 0
if (alphalevel > 0 && flag == 0) {
alphalevel -= .05f;
changealpha ();
} else if ((alphalevel == 0 || flag == 1) && alphalevel < .20) {
alphalevel += .05f;
changealpha ();
Debug.Log (alphalevel);
flag = 1;
} else if (alphalevel == .20) {
flag = 0;
}
countdown-=Time.smoothDeltaTime;
yield return null;
}
}
alphalevel = 1f;
changealpha ();
laserfield.gameObject.tag = "Laser";
flag2 = 0;
}
//heres a function to change transparency of player when a powerup is in effect
void changealpha()
{
EffectiveTo.GetComponent<SpriteRenderer> ().color = new Color (1f, 1f, 1f, alphalevel);
}
}
Use Coroutine's for your advantage:
void OnTriggerEnter2D(Collider2D other)
{
StartCoroutine(PowerUp());
}
private IEnumerator PowerUp()
{
countDown = 10f;
while (countDown >= 0)
{
// Logic during the 10 seconds
countDown -= Time.smoothDeltaTime;
yield return null;
}
}
What is happening is that when you disable the gameobject, the script that this gameobject has stop working too.
In your case when the OnTriggerEnter2D is fired you're setting you gameobject to false gameObject.SetActive(false); which means that this script will stop working because you've also placed this script on the gameobject you've just disabled.
You should move the OnTriggerEnter2D event on the other object that dosen't get disabled and you can disable this gameobject from there. What you do in Update would also be moved to that other gameobject.
From Unity documentation:
Making a GameObject inactive will disable every component, turning off any attached renderers, colliders, rigidbodies, scripts, etc... Any scripts that you have attached to the GameObject will no longer have Update() called, for example.

Categories