크리티컬과 데미지 연산 공식: 기본 공격력, 스킬 계수, 크리티컬 배율 메커니즘

게임 데미지 연산의 기초인 기본 공격력, 스킬 계수, 크리티컬 판정 및 배율 연산 메커니즘을 알아보고 방어력 감쇄 모델과 C# 실무 연산 코드를 살펴봅니다.

✓ 복사 완료!
챕터수치 공식 & 밸런싱
난이도중급
상태● 검토 완료
대상 엔진
Engine Agnostic
최종 업데이트
크리티컬과 데미지 연산 공식: 기본 공격력, 스킬 계수, 크리티컬 배율 메커니즘

게임 데미지 연산의 기본 구조

게임에서 공격을 실행할 때 발생하는 데미지는 단순히 공격자의 단일 수치만으로 결정되지 않습니다. 기본 공격력, 스킬 계수, 크리티컬 배율, 방어력 등이 복합적으로 작용하여 최종 타격 값이 산출됩니다.

한 가지 단순한 예시 공식은 다음과 같습니다. 게임마다 곱연산과 합연산의 순서, 버프 적용 위치가 다르므로 보편 규칙으로 보면 안 됩니다.

Damageraw=BaseAttack×SkillCoefficient×CriticalMultiplierDamage_{raw} = BaseAttack \times SkillCoefficient \times CriticalMultiplier

이 형태는 항목을 추가해 확장하기 쉽지만, 실제 적용 순서와 중첩 규칙은 프로젝트의 전투 설계에서 정해야 합니다.

기본 공격력과 스킬 계수 및 크리티컬 배율이 종합적으로 작용하는 데미지 연산 개요

데미지 연산 파이프라인 설계

데미지 계산은 단계별 연산 순서를 명확히 정의하는 것이 중요합니다. 연산 순서가 모호해지면 버프나 크리티컬 효과가 의도와 다르게 폭증하는 문제가 발생할 수 있습니다.

flowchart TD
    A[공격 발생] --> B[기본 공격력 계산]
    B --> C[스킬 계수 곱산]
    C --> D[크리티컬 확률 판정]
    D -- 크리티컬 발생 --> E[크리티컬 배율 적용]
    D -- 일반 타격 --> F[기본 배율 1.0 적용]
    E --> G[방어력 및 저항 감소 연산]
    F --> G
    G --> H[최종 데미지 출력]

1. 기본 공격력 산출

캐릭터의 순수 스탯과 장비 수치, 패시브 버프를 결합합니다. 이때 고정 합산 수치와 비율 증가 수치가 함께 적용됩니다.

BaseAttack=(StatBase+EquipmentAttack)×(1+AttackBuffPercent)BaseAttack = (StatBase + EquipmentAttack) \times (1 + AttackBuffPercent)

2. 스킬 계수 적용

각 스킬이 가진 독자적인 계수를 곱해 원시 데미지를 생성합니다.

Damageskill=BaseAttack×SkillCoefficientDamage_{skill} = BaseAttack \times SkillCoefficient

3. 크리티컬 판정 및 배율 적용

공격 시점에 난수를 발생시켜 크리티컬 확률 미만이면 크리티컬 판정을 내립니다. 크리티컬이 발동하면 기본 1.0에 추가 크리티컬 피해 비율을 더해 곱해줍니다.

CriticalMultiplier={1+CriticalDamage,if Critical Hit1.0,otherwiseCriticalMultiplier = \begin{cases} 1 + CriticalDamage, & \text{if Critical Hit} \\ 1.0, & \text{otherwise} \end{cases}

크리티컬 판정과 난수 시스템

독립 난수 판정에서는 표시 확률이 50%여도 크리티컬이 여러 번 연속 발생하거나 오랫동안 발생하지 않을 수 있습니다. 이를 줄이려면 독립 확률과 다른 분포를 만드는 보정 규칙을 설계할 수 있습니다.

순수 난수 방식과 의사 난수 방식의 크리티컬 발동 확률 분포 비교

PRD 또는 피티(pity) 방식은 실패가 이어질 때 다음 시도의 확률을 높이도록 설계할 수 있습니다. 이름만으로 구현이 정해지는 단일 알고리즘은 아니므로 확률 증가식, 초기화 시점, 장기 평균과 연속 결과 분포를 별도로 정의하고 시뮬레이션해야 합니다.

flowchart LR
    A[공격 시도] --> B{크리티컬 발생?}
    B -- 예 --> C[내부 누적 확률 P_actual 초기화]
    B -- 아니오 --> D[내부 누적 확률 P_actual 증가]

방어력 감쇄 모델과 최종 데미지 산출

원시 데미지가 계산된 후에는 피격자의 방어 스탯을 적용할 수 있습니다. 다음은 서로 다른 동작을 만드는 두 가지 예시 모델입니다.

감산형 방어력 모델

고전 RPG에서 흔히 쓰이는 방식으로 방어력 수치만큼 데미지를 직접 차감합니다.

FinalDamage=max⁡(1,Damageraw−Defense)FinalDamage = \max(1, Damage_{raw} - Defense)

구현이 직관적이지만 방어력이 공격력보다 높아지면 데미지가 최소 수치로 고정되는 한계가 있습니다.

비율 감쇄형 방어력 모델

대중적인 MOBA나 3D 액션 RPG에서 쓰이는 모델로 방어력이 높아질수록 효율이 점진적으로 감소합니다.

FinalDamage=Damageraw×(KK+max⁡(0,Defense))FinalDamage = Damage_{raw} \times \left( \frac{K}{K + \max(0, Defense)} \right)

여기서는 방어력이 0 이상이라고 가정합니다. KK는 프로젝트가 정하는 양수 상수이며, 방어력이 KK일 때 받는 피해 비율은 50%입니다. 코드 예시의 K=100K=100은 설명용 시작값입니다.

C# 기반 데미지 계산기 실무 예제

다음은 Unity 등 C# 환경에서 실무적으로 활용할 수 있는 데미지 연산 시스템 예제 코드입니다.

using System;

public struct AttackData
{
    public float BaseAttack;
    public float SkillCoefficient;
    public float CriticalChance;   // 0.0 ~ 1.0
    public float CriticalDamage;   // 0.5 = +50% 추가 피해 (총 1.5배)
}

public struct DefenseData
{
    public float Armor;
    public float DefenseConstant; // 비율 감쇄 상수 K
}

public class DamageCalculator
{
    private static readonly Random RandomGenerator = new Random();

    public static (int finalDamage, bool isCritical) CalculateDamage(AttackData attacker, DefenseData target)
    {
        // 1. 기본 데미지 연산
        float rawDamage = attacker.BaseAttack * attacker.SkillCoefficient;

        // 2. 크리티컬 판정
        double roll = RandomGenerator.NextDouble();
        bool isCritical = roll < attacker.CriticalChance;

        // 3. 크리티컬 배율 적용
        float criticalMultiplier = isCritical ? (1.0f + attacker.CriticalDamage) : 1.0f;
        float damageAfterCrit = rawDamage * criticalMultiplier;

        // 4. 방어력 비율 감쇄 적용 (K / (K + Armor))
        float defenseConstant = target.DefenseConstant > 0 ? target.DefenseConstant : 100.0f;
        float mitigationRatio = defenseConstant / (defenseConstant + Math.Max(0, target.Armor));
        float mitigatedDamage = damageAfterCrit * mitigationRatio;

        // 5. 최종 데미지 정수 변환 (최소 1 보장)
        int finalDamage = Math.Max(1, (int)Math.Floor(mitigatedDamage));

        return (finalDamage, isCritical);
    }
}

연산 시 주의사항: 부동소수점 오차와 정밀도

  1. 부동소수점 오차: float 연산의 반올림 차이는 결과에 영향을 줄 수 있습니다. 서버와 클라이언트의 일치를 요구한다면 고정 소수점 또는 정수형 스케일링 같은 규칙을 고려하되, 범위·절사 방식·오버플로를 함께 정의하고 검증해야 합니다.
  2. 절사 및 반올림 기준: 데미지 표기 시 절사(Floor) 또는 반올림(Round) 중 어떤 규칙을 적용할지 사전에 기획 기준을 명확히 세워야 수치 불일치 버그를 예방할 수 있습니다.