Forum begins after the advertisement:
[Part 3] Bat Not Doing Damage
Home › Forums › Video Game Tutorial Series › Creating a Metroidvania in Unity › [Part 3] Bat Not Doing Damage
- This topic has 3 replies, 3 voices, and was last updated 1 week, 6 days ago by
Terence.
-
AuthorPosts
-
March 19, 2025 at 10:41 am #17571::
My crawler is doing damage so I believe my enemy script is fine. Including it regardless though:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class Enemy : MonoBehaviour { [SerializeField] protected float health; [SerializeField] protected float recoilLength; [SerializeField] protected float recoilFactor; [SerializeField] protected bool isRecoiling = false; [SerializeField] protected float speed; [SerializeField] protected float damage; [SerializeField] protected GameObject orangeBlood; protected float recoilTimer; protected Rigidbody2D rb; protected SpriteRenderer sr; protected Animator anim; protected enum EnemyStates { Crawler_Idle, Crawler_Flip, Bat_Idle, Bat_Chase, Bat_Stunned, Bat_Death, } protected EnemyStates currentEnemyState; protected virtual EnemyStates GetCurrentEnemyState { get { return currentEnemyState; } set { if(currentEnemyState != value) { currentEnemyState = value; ChangeCurrentAnimation(); } } } // Start is called before the first frame update protected virtual void Start() { rb = GetComponent<Rigidbody2D>(); sr = GetComponent<SpriteRenderer>(); anim = GetComponent<Animator>(); } // Update is called once per frame protected virtual void Update() { if(isRecoiling) { if(recoilTimer < recoilLength) { recoilTimer += Time.deltaTime; } else { isRecoiling = false; recoilTimer = 0; } } else { UpdateEnemyStates(); } } public virtual void EnemyGetsHit(float _damageDone, Vector2 _hitDirection, float _hitForce) { health -= _damageDone; if(!isRecoiling) { GameObject _orangeBlood = Instantiate(orangeBlood, transform.position, Quaternion.identity); Destroy(_orangeBlood, 5.5f); rb.linearVelocity = -_hitForce * recoilFactor * _hitDirection; } } protected void OnTriggerStay2D(Collider2D _other) { if(_other.gameObject.CompareTag("Player") && !PlayerController.Instance.pState.invincible && health > 0) { Attack(); PlayerController.Instance.HitStopTime(0, 5, 0.5f); } } protected virtual void Death(float _destroyTime) { Destroy(gameObject, _destroyTime); } protected virtual void UpdateEnemyStates() { } protected virtual void ChangeCurrentAnimation() { } protected void ChangeState(EnemyStates _newState) { GetCurrentEnemyState = _newState; } protected virtual void Attack() { PlayerController.Instance.TakeDamage(damage); } } using System.Collections; using System.Collections.Generic; using UnityEngine; public class Bat : Enemy { [SerializeField] private float chaseDistance; [SerializeField] private float stunDuration; float timer; // Start is called once before the first execution of Update after the MonoBehaviour is created protected override void Start() { base.Start(); ChangeState(EnemyStates.Bat_Idle); } protected override void UpdateEnemyStates() { float _dist = Vector2.Distance(transform.position, PlayerController.Instance.transform.position); switch (GetCurrentEnemyState) { case EnemyStates.Bat_Idle: if (_dist < chaseDistance) { ChangeState(EnemyStates.Bat_Chase); } break; case EnemyStates.Bat_Chase: rb.MovePosition(Vector2.MoveTowards(transform.position, PlayerController.Instance.transform.position, Time.deltaTime * speed)); FlipBat(); break; case EnemyStates.Bat_Stunned: timer += Time.deltaTime; if (timer > stunDuration) { ChangeState(EnemyStates.Bat_Idle); timer = 0; } break; case EnemyStates.Bat_Death: Death(Random.Range(5, 10)); break; } } public override void EnemyGetsHit(float _damageDone, Vector2 _hitDirection, float _hitForce) { base.EnemyGetsHit(_damageDone, _hitDirection, _hitForce); if (health > 0) { ChangeState(EnemyStates.Bat_Stunned); } else { ChangeState(EnemyStates.Bat_Death); } } protected override void Death(float _destroyTime) { rb.gravityScale = 12; base.Death(_destroyTime); } protected override void ChangeCurrentAnimation() { anim.SetBool("Idle", GetCurrentEnemyState == EnemyStates.Bat_Idle); anim.SetBool("Chase", GetCurrentEnemyState == EnemyStates.Bat_Chase); anim.SetBool("Stunned", GetCurrentEnemyState == EnemyStates.Bat_Stunned); if (GetCurrentEnemyState == EnemyStates.Bat_Death) { anim.SetTrigger("Death"); } } void FlipBat() { if (PlayerController.Instance.transform.position.x < transform.position.x) { sr.flipX = true; } else { sr.flipX = false; } } }
View post on imgur.com
March 19, 2025 at 10:51 am #17573::It looks like you’re working on a Unity project involving enemies, specifically a Bat enemy that inherits from a base Enemy class. However, you mentioned that your “crawler is doing damage,” which suggests there might be an issue with how damage and states are handled for your enemies.
Here are some suggestions to troubleshoot your code:
-
Check Damage Application: Ensure that the damage is being calculated and applied correctly. In your
EnemyGetsHit
method, you’re reducing the health, but make sure that the_damageDone
value is correct and greater than zero when the enemy gets hit. -
Recoil Logic: Your recoil logic seems to be functioning, but make sure that the
_hitDirection
and_hitForce
are being passed correctly when callingEnemyGetsHit()
. If the enemy isn’t recoiling as expected, verify the values used during the call. -
State Transitions: Check if the state transitions are occurring as intended. For example, make sure that the enemy transitions to
Bat_Stunned
after taking damage. You can add debug logs to see if the correct states are being hit:Debug.Log($"Enemy State: {GetCurrentEnemyState}");
-
Animation Handling: Ensure your animations are set up correctly in the Animator. The parameters being set (
Idle
,Chase
,Stunned
, etc.) should match the conditions in yourChangeCurrentAnimation()
function. -
Collision Detection: In the
OnTriggerStay2D
function, ensure that the collision detection with the player is working properly. If the player’sinvincible
state is never false, the enemy won’t attack. You might want to log when the enemy is trying to attack. -
Adjusting Rigidbody Settings: Make sure that the Rigidbody2D settings for your enemy (like gravity scale, friction, etc.) are set correctly. If the enemy is behaving unexpectedly, it might be due to physics settings.
-
Debugging: Use Unity’s Debugging tools to step through the code while it’s running. Set breakpoints in your methods to inspect values when the enemy takes damage or changes states.
Here’s a small snippet to add debugging:
public override void EnemyGetsHit(float _damageDone, Vector2 _hitDirection, float _hitForce) { Debug.Log($"Enemy hit: Damage: {_damageDone}, Health before hit: {health}"); base.EnemyGetsHit(_damageDone, _hitDirection, _hitForce); Debug.Log($"Health after hit: {health}"); if (health > 0) { ChangeState(EnemyStates.Bat_Stunned); } else { ChangeState(EnemyStates.Bat_Death); } }
- Review Serialization: Ensure that your serialized fields are set correctly in the Unity editor. Sometimes, values could be zero or not as expected, leading to unintended behavior.
If you provide more context on what specifically isn’t working or what kind of damage is happening, I can offer more targeted advice!
March 19, 2025 at 11:47 am #17574::So the crawler and bat both should do damage on connection with the player, I have even added a new enemy class in the former of a charger. The crawler and charger do damage when touching the player, the bat still does not. Each enemy will receive damage when hit by the player, all animations work, but the bat, even after changing damage numbers and looking through the code, still won’t do damage to the player.
has upvoted this post. March 19, 2025 at 11:51 am #17575::It sounds like you’re working on a game where different enemy types interact with the player in specific ways. Since the bat is not dealing damage as expected, there are a few areas you can check in your code:
-
Collision Detection: Ensure that the bat’s collision detection with the player is implemented correctly. Check if the bat’s hitbox is properly defined and that the collision detection logic is working as intended.
if bat.rect.colliderect(player.rect): player.take_damage(bat.damage)
-
Damage Handling: Verify that the bat’s damage is being applied correctly. Make sure that the method responsible for dealing damage (e.g.,
player.take_damage()
) is being called when a collision occurs. -
Enemy State: Check if the bat is in the correct state when it comes into contact with the player. If the bat is in a state where it shouldn’t deal damage (like being stunned or inactive), it won’t hurt the player.
-
Animation Events: If your bat has animations, ensure that damage is not tied to a specific animation state that’s not being triggered. You might want to check if the animation is playing correctly when the bat collides with the player.
-
Debugging: Add some debugging statements to track when the collision happens and whether the damage is being applied. For example:
if bat.rect.colliderect(player.rect): print("Bat collided with player!") player.take_damage(bat.damage)
-
Compare with Other Enemies: Since you mentioned that the crawler and charger do deal damage, compare the implementation of the bat with those enemies. Look for any differences in how damage is calculated or how collisions are managed.
-
Game Loop Logic: Review the game loop to ensure that the bat’s updates and collision checks are being called regularly, similar to the other enemies.
If you can share specific snippets of your code related to the bat’s collision detection and damage application, I can provide more targeted help.
March 19, 2025 at 11:51 am #17576March 19, 2025 at 11:55 am #17577::It sounds like you managed to resolve the issue with your game where enemies were dealing damage to the player. That’s great to hear! If you have any further questions or need help with another part of your code or game development, feel free to ask. Happy coding!
March 19, 2025 at 6:04 pm #17581 -
-
AuthorPosts
- You must be logged in to reply to this topic.
Advertisement below: