f8b21af4be
10_Wiki/Topics 대규모 정리: - 오류 캡처/미완성 stub 문서 227개 제거 - 교차폴더 중복 43클러스터 병합 (63파일 → redirect) - 링크명 정규화: 깨진 링크 수정·redirect 직결·개념 매핑 ~2,400건 - 카테고리 MOC 6개 신규 생성 - Graph 섹션 미해결 related-keyword 링크 10,058건 제거 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.3 KiB
7.3 KiB
id, title, category, status, canonical_id, aliases, duplicate_of, source_trust_level, confidence_score, verification_status, tags, raw_sources, last_reinforced, github_commit, tech_stack
| id | title | category | status | canonical_id | aliases | duplicate_of | source_trust_level | confidence_score | verification_status | tags | raw_sources | last_reinforced | github_commit | tech_stack | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| wiki-2026-0508-control-points | Control Points | 10_Wiki/Topics | verified | self |
|
none | A | 0.85 | applied |
|
2026-05-10 | pending |
|
Control Points
매 한 줄
"매 spatial objective — 매 team 이 매 zone 의 occupy 통해 score/win.". Control Points는 multiplayer game 의 가장 ubiquitous objective primitive. Domination, KOTH, Capture-and-Hold, Push, Hardpoint 모두 변형. Team Fortress 2, Battlefield, Overwatch, Apex, CS Bombsite (variant), Splatoon (area-based) 의 핵심. 2026년 server-authoritative netcode + lag compensation 패턴 매 stable.
매 핵심
매 variants
| Variant | Mechanic |
|---|---|
| Domination | Multiple points, hold majority for tickets/score |
| KOTH | Single point, hold-time wins |
| Capture & Hold | Capture sequentially, last team standing |
| Hardpoint | Single rotating point, score over time |
| Push/Payload | Mobile control point along track |
| Linear (5CP TF2) | Sequential capture, central pivot |
매 mechanics
- Capture progress: 0~100%, increases with attackers in zone.
- Multi-capture rate: more attackers → faster (capped, e.g. 2x at 2+).
- Contest: defenders inside → progress paused.
- Lock/unlock: previous point capture unlocks next.
- Decay: progress drops when zone empty (configurable).
- Overtime: contested point prevents game end.
매 design principles
- Sightline balance: defenders 의 advantage 와 attacker chokes 의 균형.
- Capture time: too short → trivial, too long → stalemate. 5-15s typical.
- Cap-zone size: encourages clustering vs spread.
- Spawn distance: defender respawn 가 너무 가까우면 attack 불가.
매 응용
- FPS multiplayer modes (Overwatch, BF, CoD).
- MOBA jungle camps / objectives (Roshan, Drake areas).
- RTS resource nodes (StarCraft expansions).
- MMO PvP zones (WoW battlegrounds).
💻 패턴
Unity C# — control point trigger
using UnityEngine;
using Unity.Netcode;
public class ControlPoint : NetworkBehaviour {
public NetworkVariable<float> Progress = new(0f);
public NetworkVariable<int> OwnerTeam = new(-1);
[SerializeField] private float captureRate = 10f; // pct/sec per attacker
[SerializeField] private float maxRate = 20f;
private readonly Dictionary<int, int> teamCount = new();
private void OnTriggerEnter(Collider other) {
if (!IsServer) return;
if (other.TryGetComponent<Player>(out var p)) {
teamCount.TryGetValue(p.Team, out var n);
teamCount[p.Team] = n + 1;
}
}
private void OnTriggerExit(Collider other) {
if (!IsServer) return;
if (other.TryGetComponent<Player>(out var p)
&& teamCount.TryGetValue(p.Team, out var n)) {
teamCount[p.Team] = Mathf.Max(0, n - 1);
}
}
private void FixedUpdate() {
if (!IsServer) return;
var teams = new List<KeyValuePair<int,int>>(teamCount);
teams.Sort((a, b) => b.Value.CompareTo(a.Value));
if (teams.Count == 0 || teams[0].Value == 0) return;
// Contested: top two teams equal & nonzero
if (teams.Count > 1 && teams[0].Value == teams[1].Value) return;
var attacker = teams[0];
var rate = Mathf.Min(maxRate, captureRate * Mathf.Sqrt(attacker.Value));
if (OwnerTeam.Value == attacker.Key) {
Progress.Value = Mathf.Min(100f, Progress.Value + rate * Time.fixedDeltaTime);
} else {
Progress.Value = Mathf.Max(0f, Progress.Value - rate * Time.fixedDeltaTime);
if (Progress.Value <= 0f) OwnerTeam.Value = attacker.Key;
}
}
}
Godot 4 / GDScript
extends Area3D
class_name ControlPoint
@export var capture_rate: float = 10.0
var progress: float = 0.0
var owner_team: int = -1
var team_in_zone: Dictionary = {}
func _physics_process(delta: float) -> void:
if not multiplayer.is_server(): return
var top_team := -1
var top_count := 0
var contested := false
for team in team_in_zone:
var n: int = team_in_zone[team]
if n > top_count:
top_count = n
top_team = team
contested = false
elif n == top_count and n > 0:
contested = true
if contested or top_count == 0: return
var rate = capture_rate * sqrt(top_count)
if owner_team == top_team:
progress = min(100.0, progress + rate * delta)
else:
progress = max(0.0, progress - rate * delta)
if progress <= 0.0:
owner_team = top_team
_notify_capture(top_team)
Server-authoritative state with lag compensation
// Server stores state snapshots for last 1s
private readonly CircularBuffer<Snapshot> history = new(60);
public bool WasInsideAtTime(Vector3 playerPos, float clientTime) {
var snap = history.SampleAt(clientTime);
return snap.Bounds.Contains(playerPos);
}
Configurable progression (data-driven)
{
"id": "cp_central",
"captureTimeSeconds": 8,
"multiCapMultiplier": [1.0, 1.5, 1.75, 2.0],
"decayRate": 0.5,
"unlockedBy": ["cp_a", "cp_b"],
"scoresPerSecond": 10
}
UI broadcast (client-side prediction visual)
// Client receives Progress NetworkVariable changes,
// interpolates between ticks for smooth bar fill
useEffect(() => {
const start = performance.now();
const startVal = displayedProgress;
const targetVal = serverProgress;
const tick = () => {
const t = Math.min(1, (performance.now() - start) / 100);
setDisplayedProgress(startVal + (targetVal - startVal) * t);
if (t < 1) requestAnimationFrame(tick);
};
tick();
}, [serverProgress]);
매 결정 기준
| 상황 | Approach |
|---|---|
| Casual fast-match | KOTH, single-point, 3-5 min rounds |
| Competitive | Linear/5CP, longer rounds, overtime |
| Asymmetric | Push/Payload (attack vs defend) |
| Objective rotation | Hardpoint (rotating zone keeps action moving) |
| Large maps | Domination (multiple distributed) |
기본값: server-authoritative + 5-10s capture + multi-cap multiplier + decay + contested-pause + overtime.
🔗 Graph
- 변형: Domination
- Adjacent: Lag Compensation
🤖 LLM 활용
언제: multiplayer mode design, level layout review, balance tuning, netcode design for objectives. 언제 X: single-player, asynchronous (turn-based), pure deathmatch (no objective).
❌ 안티패턴
- Client-authoritative capture: trivially exploitable — server-side only.
- Spawn too close to objective: defender immortal — distance + lockout window.
- No contested-pause: solo defender can't stall — feels unfair.
- Capture too short: zerg wins, no skill — 8-12s standard.
- No decay: half-cap then leave is permanent — partial progress decay.
🧪 검증 / 중복
- Verified (Valve TF2 design / Blizzard Overwatch dev blogs / GDC talks 2018-2024).
- 신뢰도 A-.
🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — variants + Unity/Godot impl + netcode |