> ## Documentation Index
> Fetch the complete documentation index at: https://docs-unity.molca.id/llms.txt
> Use this file to discover all available pages before exploring further.

# ScoringConfig

> ScoringType enum and CalculateScore behavior.

**File:** `Assets/_MolcaSDK/_VR/Scripts/Scenario/Scoring/ScoringConfig.cs`

## Aggregation layers

`ScoringConfig` instances are used at step, activity, and scenario levels:

```mermaid theme={null}
flowchart TB
  subgraph Scenario["Scenario"]
    SC[ScenarioScoring + ScoringConfig]
  end
  subgraph Activity["Activity"]
    AC[ActivityScoring + ScoringConfig]
  end
  subgraph Step["Step"]
    ST[StepScoringAuxiliary + ScoringConfig]
  end
  ST --> AC
  AC --> SC
```

See [Step scoring auxiliary](/vr/scoring/step-scoring-auxiliary), [Activity scoring](/vr/scoring/activity-scoring), and [Scenario scoring](/vr/scoring/scenario-scoring).

## ScoringType reference

Enum values and behavior match **`ScoringConfig.CalculateScore(float timeTaken, float accuracy = 1f)`** in `ScoringConfig.cs`. After the switch, the result is multiplied by **`scoreMultiplier`**; if **`allowNegativeScore`** is false, the final score is clamped to **≥ 0**.

**`IsTimeBased()`** is true only for **TimeBonus**, **TimePenalty**, and **Countdown** (drives [StepScoringAuxiliary](/vr/scoring/step-scoring-auxiliary) **`OnStepUpdate`** refresh).

| `ScoringType`     | Uses `timeTaken` | Uses `accuracy` | Primary serialized fields                                                       | `CalculateScore` (before multiplier & negative clamp)                                                                                                                                                                |
| ----------------- | ---------------- | --------------- | ------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`None`**        | —                | —               | *(none)*                                                                        | **0**                                                                                                                                                                                                                |
| **`PointValue`**  | Ignored          | Ignored         | **`basePoints`**                                                                | **`basePoints`**                                                                                                                                                                                                     |
| **`Binary`**      | Ignored          | **Yes** (0–1)   | **`correctPoints`**, **`incorrectPoints`**                                      | **`correctPoints`** if **`accuracy >= 0.5`**, else **`incorrectPoints`**                                                                                                                                             |
| **`TimeBonus`**   | **Yes**          | Ignored         | **`targetTimeSeconds`**, **`maxTimeSeconds`**, **`minPoints`**, **`maxPoints`** | If **`timeTaken <= targetTime`** → **`maxPoints`**. If **`timeTaken >= maxTime`** → **`minPoints`**. Between: **linear lerp** from **`maxPoints`** at **`targetTime`** down toward **`minPoints`** at **`maxTime`**. |
| **`TimePenalty`** | **Yes**          | Ignored         | **`maxPoints`**, **`pointsPerSecond`**, **`minPoints`**                         | **`maxPoints - (timeTaken * pointsPerSecond)`**, then **`max(score, minPoints)`** (floor)                                                                                                                            |
| **`Countdown`**   | **Yes**          | Ignored         | **`countdownDuration`**, **`pointsPerSecond`**                                  | **`remaining * pointsPerSecond`** where **`remaining = max(0, countdownDuration - timeTaken)`**                                                                                                                      |
| **`Accuracy`**    | Ignored          | **Yes** (0–1)   | **`minPoints`**, **`maxPoints`**                                                | **`Lerp(minPoints, maxPoints, Clamp01(accuracy))`**                                                                                                                                                                  |

### Shared tuning (all types except `None`)

| Field                    | Role                                                                   |
| ------------------------ | ---------------------------------------------------------------------- |
| **`scoreMultiplier`**    | Applied to the computed score after the **`switch`**.                  |
| **`allowNegativeScore`** | If **false**, final score is **`max(0, score)`** after the multiplier. |

### `GetMaxPossibleScore()` (UI caps & normalization)

| `ScoringType`                                      | Returns (before needing final clamp in callers)             |
| -------------------------------------------------- | ----------------------------------------------------------- |
| **`None`**                                         | **0**                                                       |
| **`PointValue`**                                   | **`basePoints * scoreMultiplier`**                          |
| **`Binary`**                                       | **`Max(correctPoints, incorrectPoints) * scoreMultiplier`** |
| **`TimeBonus`**, **`TimePenalty`**, **`Accuracy`** | **`maxPoints * scoreMultiplier`**                           |
| **`Countdown`**                                    | **`countdownDuration * pointsPerSecond * scoreMultiplier`** |

## Implementation detail

Prefer calling **`CalculateScore`** / **`GetMaxPossibleScore`** on **`ScoringConfig`** rather than duplicating formulas in gameplay code. **`StepScoringAuxiliary`** sets **`accuracy`** for **Binary** / **Accuracy** via **`SetCorrect`**, **`SetIncorrect`**, **`SetAccuracy`**, **`SetAccuracyPercent`** before finalize — see [Step scoring auxiliary](/vr/scoring/step-scoring-auxiliary).

## When to use

Embed **`ScoringConfig`** (serialized class, not necessarily a standalone asset) wherever scoring is configured: **[StepScoringAuxiliary](/vr/scoring/step-scoring-auxiliary)**, **[ActivityScoring](/vr/scoring/activity-scoring)**, **[ScenarioScoring](/vr/scoring/scenario-scoring)**. Choose **None** when the layer should not contribute numeric score but you still want a placeholder in the Inspector.

## Troubleshooting

* **Scores always zero** — **Type** may be **None**; or time-based config has **`maxPoints`** / windows set so the formula yields 0 at current **`timeTaken`** / **`accuracy`**.
* **Binary feels inverted** — Accuracy is **0–1**: use **`StepScoringAuxiliary.SetCorrect`** / **`SetIncorrect`** (or **`SetResult(bool)`**) so **`CalculateScore`** treats correct as **0.5 and above** and incorrect **below 0.5**.
* **Unexpected negatives** — Enable **`allowNegativeScore`** or raise **`minPoints`** / adjust **TimePenalty** rate; final value is still multiplied by **`scoreMultiplier`**.

## Related

* [Recipe: Add scoring to VR activities](/recipes/add-vr-activity-scoring) — step-by-step guide for configuring scoring in VR training activities

## Unity Editor

<Frame hint="Embedded ScoringConfig on StepScoringAuxiliary or standalone asset if you use ScriptableObject variants." caption="ScoringConfig fields">
  <img src="https://mintlify.s3.us-west-1.amazonaws.com/ptmolcateknologinusantara/images/features/vr/scoring/scoring-config-inspector.png" alt="ScoringConfig in Unity Inspector" />
</Frame>
