I’m trying to code an enemy the will deal damage to the player when it touches the player but it deals damage no matter what or where you are in comparison to the enemy (It seems to deal damage when the distance between the player and enemy changes). I have no idea why it isn’t working properly.
Here is the code for my player controller
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControl : MonoBehaviour
{
[Header("Horizontal Movement Settings")]
[SerializeField] private float walkSpeed = 1f;
[Space(5)]
[Header("Advanced Movement Settings")]
[SerializeField] private float dashSpeed;
[SerializeField] private float dashTime;
[SerializeField] private float dashCooldown;
[Space(5)]
[Header("Advanced Jump Settings")]
private float jumpBufferCounter = 0f;
[SerializeField] private float jumpBufferFrames;
private float coyoteTimeCounter = 0f;
[SerializeField] private float coyoteTime;
private int airJumpCounter = 0;
[SerializeField] int maxAirJumps;
[Space(5)]
[Header("Ground Check Settings")]
[SerializeField] private float jumpHeight = 45f;
[SerializeField] private Transform groundCheckPoint;
[SerializeField] private float groundCheckY = 0.2f;
[SerializeField] private float groundCheckx = 0.5f;
[SerializeField] private LayerMask whatIsGround;
[Space(5)]
[Header("Attacking")]
[SerializeField] float timeBetweenAttack;
float timeSinceAttack;
bool attack = false;
[SerializeField] float damage;
[SerializeField] Transform SideAttackTransform;
[SerializeField] Transform UpAttackTransform;
[SerializeField] Transform DownAttackTransform;
[SerializeField] Vector2 SideAttackArea;
[SerializeField] Vector2 UpAttackArea;
[SerializeField] Vector2 DownAttackArea;
[SerializeField] LayerMask attackableLayer;
[Space(5)]
[Header("Health")]
public int health;
public int maxHealth;
[Space(5)]
[Header("Recoil")]
[SerializeField] int recoilXSteps = 5;
[SerializeField] int recoilYSteps = 5;
[SerializeField] float recoilXSpeed = 100;
[SerializeField] float recoilYSpeed = 100;
int stepsXRecoiled;
int stepsYRecoiled;
public PlayerStatesList pState;
public static PlayerControl Instance;
private Rigidbody2D rb;
Animator anim;
private float xAxis, yAxis;
private bool canDash = true;
private bool dashed;
private float gravity;
public global::System.Single WalkSpeed { get => walkSpeed; set => walkSpeed = value; }
private void Awake()
{
if(Instance != null && Instance != this)
{
Destroy(gameObject);
}
else
{
Instance = this;
}
Health = maxHealth;
}
void Start()
{
pState = GetComponent<PlayerStatesList>();
rb = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
gravity = rb.gravityScale;
}
void OnDrawGizmosSelected()
{
// Draw a yellow cube at the transform position
Gizmos.color = Color.red;
Gizmos.DrawWireCube(SideAttackTransform.position, SideAttackArea);
Gizmos.DrawWireCube(UpAttackTransform.position, UpAttackArea);
Gizmos.DrawWireCube(DownAttackTransform.position, DownAttackArea);
}
// Update is called once per frame
void Update()
{
UpdateJumpVariables();
GetInputs();
if (pState.dashing) return;
Move();
Jump();
StartDash();
Flip();
Attack();
Recoil();
if (isTouchingEnemy)
{
TakeDamage(1);
}
}
void GetInputs()
{
xAxis = Input.GetAxisRaw("Horizontal");
yAxis = Input.GetAxisRaw("Vertical");
attack = Input.GetMouseButtonDown(0);
}
void Flip()
{
if (xAxis < 0)
{
transform.localScale = new Vector2(-Mathf.Abs(transform.localScale.x), transform.localScale.y);
pState.lookingRight = false;
}
else if (xAxis > 0)
{
transform.localScale = new Vector2(Mathf.Abs(transform.localScale.x), transform.localScale.y);
pState.lookingRight = true;
}
}
private void Move()
{
rb.linearVelocity = new Vector2(walkSpeed * xAxis, rb.linearVelocity.y);
}
void StartDash()
{
if (Input.GetButtonDown("Dash") && canDash && !dashed)
{
StartCoroutine(Dash());
dashed = true;
}
if (Grounded())
{
dashed = false;
}
}
IEnumerator Dash()
{
canDash = false;
pState.dashing = true;
rb.gravityScale = 0;
rb.linearVelocity = new Vector2(transform.localScale.x * dashSpeed, 0);
yield return new WaitForSeconds(dashTime);
rb.gravityScale = gravity;
pState.dashing = false;
yield return new WaitForSeconds(dashCooldown);
canDash = true;
}
void Attack()
{
timeSinceAttack += Time.deltaTime;
if (attack && timeSinceAttack >= timeBetweenAttack)
{
timeSinceAttack = 0;
anim.SetTrigger("Attacking");
if(yAxis <= 0 && Grounded())
{
Hit(SideAttackTransform, SideAttackArea, ref pState.recoilingX, recoilXSpeed);
}
else if(yAxis < 0)
{
Hit(UpAttackTransform, UpAttackArea, ref pState.recoilingY, recoilYSpeed);
}
else if(yAxis > 0 && !Grounded())
{
Hit(DownAttackTransform, DownAttackArea, ref pState.recoilingY, recoilYSpeed);
}
}
else
{
anim.ResetTrigger("Attacking");
}
}
private void Hit(Transform _attackTransform, Vector2 _attackArea, ref bool _recoilDir, float _recoilStrength)
{
Collider2D[] objectsToHit = Physics2D.OverlapBoxAll(_attackTransform.position, _attackArea, 0, attackableLayer);
List<Enemy> hitEnemies = new List<Enemy>();
if (objectsToHit.Length > 0)
{
Debug.Log("Hit");
_recoilDir = true;
}
for (int i = 0; i < objectsToHit.Length; i++)
{
Enemy e = objectsToHit[i].GetComponent<Enemy>();
if (e && !hitEnemies.Contains(e))
{
e.EnemyHit(damage, (transform.position - objectsToHit[i].transform.position).normalized, _recoilStrength);
hitEnemies.Add(e);
}
}
}
void Recoil()
{
if (pState.recoilingX)
{
if (pState.lookingRight)
{
rb.linearVelocity = new Vector2 (-recoilXSpeed, 0);
}
else
{
rb.linearVelocity = new Vector2 (recoilXSpeed, 0);
}
}
if (pState.recoilingY)
{
if (yAxis < 0)
{
rb.gravityScale = 0;
rb.linearVelocity = new Vector2 (rb.linearVelocity.x, recoilYSpeed);
}
else
{
rb.gravityScale = 0;
rb.linearVelocity = new Vector2 (rb.linearVelocity.x, -recoilYSpeed);
}
airJumpCounter = 0;
}
else
{
rb.gravityScale = gravity;
}
//stop recoil
if (pState.recoilingX && stepsXRecoiled < recoilXSteps)
{
stepsXRecoiled++;
}
else
{
StopRecoilX();
}
if (pState.recoilingY && stepsYRecoiled < recoilYSteps)
{
stepsYRecoiled++;
}
else
{
StopRecoilY();
}
if (Grounded())
{
StopRecoilY();
}
}
void StopRecoilX()
{
stepsXRecoiled = 0;
pState.recoilingX = false;
}
void StopRecoilY()
{
stepsYRecoiled = 0;
pState.recoilingY = false;
}
public void TakeDamage(float _damage)
{
if (!pState.invincible)
{
Health -= Mathf.RoundToInt(_damage);
StartCoroutine(StopTakingDamage());
}
}
IEnumerator StopTakingDamage()
{
pState.invincible = true;
yield return new WaitForSeconds(1f);
pState.invincible = false;
}
private bool isTouchingEnemy = false;
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.CompareTag("Enemy")) // Assuming enemies are tagged as "Enemy"
{
isTouchingEnemy = true;
TakeDamage(1); // Decrease health by 1
}
}
private void OnTriggerExit2D(Collider2D collision)
{
if (collision.CompareTag("Enemy"))
{
isTouchingEnemy = false;
}
}
public int Health
{
get { return health; }
set
{
if (health != value)
{
health = Mathf.Clamp(value, 0, maxHealth);
}
}
}
public bool Grounded()
{
if(Physics2D.Raycast(groundCheckPoint.position, Vector2.down, groundCheckY, whatIsGround)
|| Physics2D.Raycast(groundCheckPoint.position + new Vector3(groundCheckx, 0, 0), Vector2.down, groundCheckY, whatIsGround)
|| Physics2D.Raycast(groundCheckPoint.position + new Vector3(-groundCheckx, 0, 0), Vector2.down, groundCheckY, whatIsGround))
{
return true;
}
else
{
return false;
}
}
void Jump()
{
if (!Input.GetButton("Jump") && rb.linearVelocity.y > 0)
{
rb.linearVelocity = new Vector2(rb.linearVelocity.x, 0);
pState.jumping = false;
}
if (rb.linearVelocity.y <= 0)
{
pState.jumping = false;
}
if (!pState.jumping)
{
if (jumpBufferCounter > 0 && coyoteTimeCounter > 0)
{
rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpHeight);
pState.jumping = true;
}
else if(!Grounded() && airJumpCounter < maxAirJumps && Input.GetButtonDown("Jump"))
{
pState.jumping = true;
airJumpCounter++;
rb.linearVelocity = new Vector3(rb.linearVelocity.x, jumpHeight);
}
}
}
void UpdateJumpVariables()
{
if (Grounded())
{
pState.jumping = false;
coyoteTimeCounter = coyoteTime;
airJumpCounter = 0;
}
else
{
coyoteTimeCounter -= Time.deltaTime;
}
if (Input.GetButtonDown("Jump"))
{
jumpBufferCounter = jumpBufferFrames;
}
else
{
jumpBufferCounter = jumpBufferCounter - Time.deltaTime * 10;
}
}
}
here is my code for the generic enemy
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 PlayerControl player;
[SerializeField] protected float speed;
[SerializeField] protected float damage;
protected float recoilTimer;
protected Rigidbody2D rb;
// Start is called once before the first execution of Update after the MonoBehaviour is created
protected virtual void Start()
{
}
protected virtual void Awake()
{
rb = GetComponent<Rigidbody2D>();
player = PlayerControl.Instance;
}
// Update is called once per frame
protected virtual void Update()
{
if (health <= 0)
{
Destroy(gameObject);
}
if (isRecoiling)
{
if (recoilTimer < recoilLength)
{
recoilTimer += Time.deltaTime;
}
else
{
isRecoiling = false;
recoilTimer = 0;
}
}
}
public virtual void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
{
health -= _damageDone;
if (!isRecoiling)
{
rb.AddForce(-_hitForce * recoilFactor * _hitDirection);
isRecoiling = true;
}
}
protected void OnTriggerStay2D(Collider2D _other)
{
if(_other.CompareTag("Player") && !PlayerControl.Instance.pState.invincible);
{
Attack();
}
}
protected virtual void Attack()
{
PlayerControl.Instance.TakeDamage(damage);
}
}
her is code for the specific enemy
using UnityEngine;
public class Zombie : Enemy
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
protected override void Start()
{
rb.gravityScale = 12f;
}
protected override void Awake()
{
base.Awake();
}
// Update is called once per frame
protected override void Update()
{
base.Update();
if (!isRecoiling)
{
transform.position = Vector2.MoveTowards(transform.position, new Vector2(PlayerControl.Instance.transform.position.x, transform.position.y), speed * Time.deltaTime);
}
}
public override void EnemyHit(float _damageDone, Vector2 _hitDirection, float _hitForce)
{
base.EnemyHit(_damageDone, _hitDirection, _hitForce);
}
}
and here is my player state manager
using UnityEngine;
public class PlayerStatesList : MonoBehaviour
{
public bool jumping = false;
public bool dashing = false;
public bool recoilingX, recoilingY;
public bool lookingRight;
public bool invincible;
}