I have a player hitbox that I’m colliding with an enemy’s collider. My attack is active for as long as the attack button is pressed. My enemy shakes a little bit each time it is hit, but I want it to continuously shake while the player is attacking and there is a collision. Any insights?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] PlayerController controllerScript;
bool isShaking = false;
[SerializeField] float shakeAmount = 0.02f;
Vector2 startPos;
// Start is called before the first frame update
void Start()
{
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
if (isShaking)
transform.position = startPos + UnityEngine.Random.insideUnitCircle * shakeAmount;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "AttackHitBox")
{
// do some damage
isShaking = true;
// StopShaking();
Debug.Log("isAttack is: " + controllerScript.inputScript.isAttack);
}
else if (!controllerScript.inputScript.isAttack)
{
isShaking = false;
transform.position = startPos;
Debug.Log("isAttack is: " + controllerScript.inputScript.isAttack);
}
}
/* private void OnTriggerExit2D(Collider2D collision)
if (controllerScript.inputScript.isAttack)
{
isShaking = false;
transform.position = startPos;
Debug.Log("Collider Exited.");
}
else
Debug.Log(controllerScript.meleeScript.isActiveHitBox);
}
/* void StopShaking()
{
if (!controllerScript.meleeScript.isActiveHitBox)
{
isShaking = false;
transform.position = startPos;
}
else if(controllerScript.meleeScript.isActiveHitBox)
{
isShaking = true;
}
}
*/
}
It is a little hard to understand what is going on in your game here. Do you have a continuous beam hitting the enemy? Do you have an intermittent impact that is just really fast (like a machine gun or a fast swinging sword)?
It’s a fast swinging sword, but my hitbox for it set to be continuously active while the attack button is held down.
PlayerInput script:
// Update is called once per frame
void Update()
{
if (Input.GetKey(KeyCode.G))
isAttack = true;
else if (Input.GetKeyUp(KeyCode.G))
isAttack = false;
PlayerMelee script:
// Update is called once per frame
void Update()
{
if (controllerScript.inputScript.isAttack)
{
controllerScript.anim.SetBool("isAttacking", true);
attackHitBox.SetActive(true);
isActiveHitBox = true;
// StartCoroutine(DoAttack());
}
else if (!controllerScript.inputScript.isAttack)
{
controllerScript.anim.SetBool("isAttacking", false);
attackHitBox.SetActive(false);
isActiveHitBox = false;
I’m trying to find a solution to my hitbox becoming inactive, and it not being recognized by OnTriggerExit2D. If I move my player away from my enemy, moving my inactive player hitbox away and out of the collider, it works perfectly. But simply setting the hitbox with SetActive(false) isn’t enough to trigger an exit with OnTriggerExit2D. Maybe I’m misunderstanding Active. But there’s no Enabled to set to false that I see.
Yeah, when you set it inactive, everything about it is inactive, so it won’t be checking for the exit conditions anymore. Setting active false basically completely turns off that element. So next question is why are you inactivating the hitbox?
Actually, who cares about my question. It sounds an awful lot like you should be using OnTriggerStay2D instead of enter and exit. That’s triggered every frame a trigger collider is in contact and that sounds closer to what you want.
I’ll give it a shot. But do you recommend a better way to attack? I thought it was a common practice to make the hitbox disappear if you’re not using it with an attack.
Okay OnTriggerStay implemented but I still can’t find anything on staying in the trigger condition until the collider is inactive. Here’s what I have, any help is appreciated:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] PlayerController controllerScript;
bool isShaking = false;
[SerializeField] float shakeAmount = 0.02f;
Vector2 startPos;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (isShaking)
transform.position = startPos + UnityEngine.Random.insideUnitCircle * shakeAmount;
}
private void OnTriggerStay2D(Collider2D collision)
{
if (!collision.isActiveAndEnabled)
{
isShaking = false;
transform.position = startPos;
}
else if (collision.gameObject.name == "AttackHitBox")
{
startPos = transform.position;
// do some damage
isShaking = true;
Debug.Log("isAttack is: " + controllerScript.inputScript.isAttack);
}
}
/* private void ResetShake()
{
isShaking = false;
transform.position = startPos;
}
*/
/* private void OnTriggerExit2D(Collider2D collision)
{
if (controllerScript.inputScript.isAttack)
{
isShaking = false;
transform.position = startPos;
Debug.Log("isActiveHitBox: " + controllerScript.meleeScript.isActiveHitBox);
Debug.Log("Collider Exited.");
}
else
Debug.Log("isActiveHitBox: " + controllerScript.meleeScript.isActiveHitBox);
}
*/
/* void StopShaking()
{
if (!controllerScript.meleeScript.isActiveHitBox)
{
isShaking = false;
transform.position = startPos;
}
else if(controllerScript.meleeScript.isActiveHitBox)
{
isShaking = true;
}
}
*/
}
Resolved. Had to add a rb to the enemy and set it to always awake. I’m not sure how sustainable that is but it’s working for my small project:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] PlayerController controllerScript;
bool isShaking = false;
[SerializeField] float shakeAmount = 0.02f;
Vector2 startPos;
// Start is called before the first frame update
void Start()
{
startPos = transform.position;
}
// Update is called once per frame
void Update()
{
if (isShaking)
transform.position = startPos + UnityEngine.Random.insideUnitCircle * shakeAmount;
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "AttackHitBox")
{
// do some damage
isShaking = true;
Debug.Log("Collider entered, isAttack is: " + controllerScript.inputScript.isAttack);
}
}
private void OnTriggerStay2D(Collider2D collision)
{
if (collision.isActiveAndEnabled)
{
isShaking = true;
Debug.Log("Staying.");
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.gameObject.name == "AttackHitBox")
{
isShaking = false;
transform.position = startPos;
Debug.Log("Collider exited, isActiveHitBox: " + controllerScript.meleeScript.isActiveHitBox);
}
}
}
Remember, OnTriggerStay is called every frame, just like Update, so you don’t need enter or exit. Just set isshaking in the stay function to true, in update check it, do your shake if true, and reset it to false. The very next frame, ontriggerstay will be called again, and will reset it back to true if applicable. Or you could just do the shake in the ontriggerstay itself, skipping update entirely and the isshaking variable, but I’m not sure that is good practice, but you could try it.
Physics callbacks are not called every frame. They are called at the end of the simulation step so unless you are running physics per-frame, this won’t be the case. By default the simulation step happens each fixed-update.
Well, if that’s the case, you better change the documentation to reflect such.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnTriggerStay2D.html
“Sent each frame where another object…”
Needs to say something that it is restricted to physics calc frames.
I can ask about that being changed. Oh and you’re welcome. 