Crit system

Hello, I am making a 2D sidescrolling game, and I want to make critical hit system in game, but I tried few things but it didint really work, does anyone have experience with making a critical hit system for 2d game?

3 Answers

3

This is really not enough information to go on. What did you try that didn’t work? What exactly do you want a crit to do that is different from a normal hit?
If you just want some hits to randomly do more damage, you can use Random.value to get a random number.

float critChance = 0.1f;
if(Random.value <= critChance)
{
    DoDamage(critDamage);
}
else
{
    DoDamage(normalDamage);
}

Hello I tried this code

float critChance = 0.0f;
 
void IncreaseCritChance(float critInc)
{
     critChance += critInc;
 
     //Never let the crit chance go out of range
     if(critChance > 100.0f)
     {
          critChance = 100.0f;
     }
}
 
void DoAttack()
{
     float randValue = Random.value;
     if(randValue < critChance)
     {
          CritAttack();
     }
     else
     {
          Attack();
     }
}

and it didnt work. I want crit system that will make random number from 1% to 100% and make it that when that random number is same or bigger than critchance, for exaple 5% it will do damage x2,and I dont exactly know how to put the crit script into my code.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography.X509Certificates;
using TMPro;
using UnityEngine;
using UnityEngine.Events;

public class PlayerMovement : MonoBehaviour
{
    public Animator animator;

    public EssanceManager em;

    public Transform attackPoint;

    public GameObject popUpPrefab;

    public float attackRange = 0.5f;
    public int attackDamage = 40;
    public float CritDamage = 40 * 2f;
    public LayerMask enemyLayers;
    public int damage;

    public float attackRate = 3f;
    float nextAttackTime = 0f;

    private float horizontal;
    private float speed = 8f;
    private float jumpingPower = 16f;
    private bool isFacingRight = true;
    private bool inAir;

    private bool canDash = true;
    private bool isDashing;
    private float dashingPower = 150f;
    private float dashingTime = 0.2f;
    private float dashingCooldown = 1f;

    private bool doubleJump;

    [SerializeField] private Rigidbody2D rb;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private LayerMask groundLayer;
    [SerializeField] private TrailRenderer tr;

    void Update()
    {

        animator.SetBool("IsDashing", isDashing);
        animator.SetFloat("Speed", Mathf.Abs(horizontal));
        

        if (isDashing)
        {
            return;
        }

        if (Time.time >= nextAttackTime)
        {
            if (Input.GetKeyDown(KeyCode.Space))
            {
                Attack();
                nextAttackTime = Time.time + 1f / attackRate;
            }
        }
        horizontal = Input.GetAxisRaw("Horizontal");

        if(IsGrounded() && !Input.GetKey(KeyCode.W))
        {
            doubleJump = false;
        }

        if (Input.GetKeyDown(KeyCode.W))
        {
            if(IsGrounded() || doubleJump)
            {
                animator.SetTrigger("isJumping");
                rb.velocity = new Vector2(rb.velocity.x, jumpingPower);

                doubleJump = !doubleJump;
            }
        }

        if (Input.GetKeyUp(KeyCode.W) && rb.velocity.y > 0f)
        {
            rb.velocity = new Vector2(rb.velocity.x, rb.velocity.y * .5f);
        }

        if (Input.GetKeyDown(KeyCode.LeftShift) && canDash)
        {
            StartCoroutine(Dash());
        }

        Flip();
    }

    void Attack()
    {
        animator.SetTrigger("Attack");

        Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(attackPoint.position, attackRange, enemyLayers);

        foreach (Collider2D enemy in hitEnemies)
        {
            Invoke(nameof(DelayPopUps), .5f);
            enemy.GetComponent<BansheeHealth>().TakeDamage(attackDamage);
        }
    }

    private void FixedUpdate()
    {

        if (isDashing)
        {
            return;
        }
        else
        {
            rb.velocity = new Vector2(horizontal * speed, rb.velocity.y);
        }

    }

    private bool IsGrounded()
    {
        return Physics2D.OverlapCircle(groundCheck.position, 0.2f, groundLayer);
    }

    private void Flip()
    {
        if (isFacingRight && horizontal < 0f || !isFacingRight && horizontal > 0f)
        {
            isFacingRight = !isFacingRight;
            Vector3 localScale = transform.localScale;
            localScale.x *= -1f;
            transform.localScale = localScale;
        }
    }

    private IEnumerator Dash()
    {
        canDash = false;
        isDashing = true;
        float originalGravity = rb.gravityScale;
        rb.gravityScale = 0f;
        rb.velocity = new Vector2(transform.localScale.x * dashingPower, 0f);
        tr.emitting = true;
        yield return new WaitForSeconds(dashingTime);
        tr.emitting = false;
        rb.gravityScale = originalGravity;
        isDashing = false;
        yield return new WaitForSeconds(dashingCooldown);
        canDash = true;
    }
    void OnDrawGizmosSelected()
    {
        if (attackPoint == null)
            return;

        Gizmos.DrawWireSphere(attackPoint.position, attackRange);
    }

    public void DelayPopUps()
    {
        GameObject popUp = Instantiate(popUpPrefab, attackPoint.position, Quaternion.identity);
        popUp.GetComponentInChildren<TMP_Text>().text = attackDamage.ToString();
    }
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.CompareTag("Collectable"))
        {
            Destroy(other.gameObject);
            em.essenceCount++;
        }    
    }
}

Random.value gives you a number between 0 and 1 (inclusive). If you want a number between 0 and 100, you need to use Random.Range.

if(Random.Range(0f, 100f) <= critChance)

You would likely want to check for a crit in your Attack() code. If there is a crit, pass 2*attackDamage into the TakeDamage() function.