# 5. Arena Hazards During Phases
Part of [[Boss Battles with Phases]]. Prev: [[4. Timeline Intros and Phase Transitions]]. Next: [[6. Worked Example Three-Phase Boss]].
A hazard that is always on is furniture. A hazard that *arrives with a phase* is a rule change, which is what a phase is for ([[1. Boss Design and the Arena]]). The trap logic itself lives in [[Hazards, Traps and Key-Door Puzzles]] (telegraph, then damage, then cooldown). This part is only the **director** that turns those traps on and off from `PhaseDefinition` data.
## 5.1 Id-based hazards
Give each trap a stable string id (`floor-ring`, `west-jets`, `collapsed-ledge`). The phase asset lists which ids to enable and disable. The director does not know what a jet is.
```csharp
using System.Collections.Generic;
using UnityEngine;
public interface IArenaHazard
{
string Id { get; }
void SetHazardActive(bool active);
}
/// <summary>
/// Finds scene hazards and applies phase enable/disable lists.
/// NOT compiled in Unity.
/// </summary>
public sealed class ArenaHazardDirector : MonoBehaviour
{
readonly Dictionary<string, IArenaHazard> _hazards = new();
void Awake()
{
var found = GetComponentsInChildren<MonoBehaviour>(true);
for (int i = 0; i < found.Length; i++)
{
if (found[i] is IArenaHazard h && !string.IsNullOrEmpty(h.Id))
_hazards[h.Id] = h;
}
}
public void SetActiveHazards(string[] enableIds, string[] disableIds)
{
if (disableIds != null)
{
for (int i = 0; i < disableIds.Length; i++)
if (_hazards.TryGetValue(disableIds[i], out var h)) h.SetHazardActive(false);
}
if (enableIds != null)
{
for (int i = 0; i < enableIds.Length; i++)
if (_hazards.TryGetValue(enableIds[i], out var h)) h.SetHazardActive(true);
}
}
}
```
A thin adapter around whatever trap component the hazards series ships:
```csharp
using UnityEngine;
public sealed class ArenaHazardProxy : MonoBehaviour, IArenaHazard
{
[SerializeField] string id = "floor-ring";
[SerializeField] Behaviour trap; // a TimedTrap, or any enabled/disabled behaviour
public string Id => id;
public void SetHazardActive(bool active)
{
if (trap != null) trap.enabled = active;
else gameObject.SetActive(active);
if (!active)
{
// Optional: if the trap exposes a ForceSafe() / Deactivate, call it so a
// mid-telegraph jet does not fire after the phase has moved on.
}
}
}
```
When you write `TimedTrap` in the hazards series, add a `ForceSafe()` and call it from here. Until then, disabling the behaviour mid-telegraph is a known pitfall (part 7): the trap should also disable its hitbox in `OnDisable`.
## 5.2 What to change per phase
| Phase | Hazard idea | Why it is a rule change |
|---|---|---|
| 1 | None, or a slow perimeter fire | Teach the boss moves in a clean floor |
| 2 | Floor ring or water that matches a slam | The tell now has a second consequence |
| 3 | Collapsed edges, smaller safe island | Space itself gets tighter |
Do not turn on every trap at Phase 2 "for difficulty." The player should be able to name what changed.
Hazards still telegraph. A phase enter is not permission to drop a rock. If a new trap appears, give it a show (a rumble, a Timeline sting, a rising glow) *before* it can damage.
## 5.3 Exercise
List three hazard ids on paper, assign them to phases, and confirm a student can explain the Phase 2 rule in one sentence. If they cannot, the hazard is noise.
## Sources
- [[Hazards, Traps and Key-Door Puzzles]]
- [[Level Up! (Review)]] Levels 11-12