协作头脑风暴
brainstorming
在实现前澄清需求、探索设计选择,并形成清晰的开发方向。
scenario-unity-gameplay【开发与工程】Use when building or debugging Unity gameplay systems: enemy AI that patrols, chases and attacks, NavMesh baking and agents (AI Navigation 2), feet sliding on agents, state machines or behavior trees, physics projectiles that tunnel, the physics spiral, layers and the collision matrix, CharacterController vs Rigidbody characters, object pooling, 'hun…
独立 GitHub 快照 · 自动分类 · 以原作者文档为准
Expert gameplay work in Unity 6.3 means every system has one owner of its state, runs at a rate someone chose, and is proven by a measurement: steps per frame, a tunneling test at the real speed, a path query through the real door, a timed transition, the worst frame at the real agent count. This skill carries the expert delta from the 6.3 manuals, AI Navigation 2, NGO and shipped games (Survival Kids, Very Very Valet), with jobs and tests run in 6000.3.21f1. If a sibling skill named here is missing from your available skills, ask the user to install it (npx skills add scenario-labs/skills --skill <name>); unattended, proceed from tool schemas and flag the gap.
REQUIRED BACKGROUND: scenario-unity-expert (channels, review loop, 6.3 traps). Install: ut_gameplay.install(P) (core AgentKit + AgentKit.Gameplay jobs + the AgentKit.Gameplay.Runtime assembly).
SweepProjectile) stopped the 300 m/s shot, and a 0.25 m sphere sweep hit a post a center ray missed: match the cast to the collider (LlamAcademy, fJyi7l2tWKo [00:09:54]).UpdateHub sorted by type (Survival Kids: same code, mean -12%, worst frame 2.18 to 1.43 ms [00:23:59]; measured here at 1,000 and 10,000 objects: mean 7 to 14% lower)..Run() (measured: 6 to 10 ms saved of 21 to 26), and only then Entities (Survival Kids [00:08:49], [00:39:15]). Decide ECS early, for large CPU-driven counts, competitive netcode or determinism (Turbo Makes Games, Bz24Jp30nkM [00:21:58]).AnticipatedNetworkVariable, AnticipatedNetworkTransform, OnReanticipate) is the building block for hand-built prediction (NGO 2.7 manual; same text in the bundled 2.13.0 docs). Server authority by default, HasAuthority over IsServer, "would a late joiner need it?" decides NetworkVariable vs RPC.ClearFloat, and 60 uncapped looping weapon sounds erased a quiet music bed at default priority. Cap frequent sounds at 10 to 15 and steal the oldest (git-amend, BgpqoRFCNOs [00:17:56]).Ask once: genre and whether play is competitive; platforms and frame budget (default 16.67 ms desktop, mobile x 0.65, scenario-unity-mobile); peak agents, projectiles and sounds; whether the player pushes and is pushed by physics; animation-driven or agent-driven locomotion; multiplayer (players, host leaving, rollback or hit rewind); existing layers, mixer and scenes; 2D or 3D (scenario-unity-2d). Defaults: 3D URP, 50 Hz, layers Environment 8, Player 9, Enemy 10, Projectile 11 with Projectile x Projectile and Enemy x Enemy off, Humanoid agent type (radius 0.5), code FSM enemies at 10 Hz, one mixer Master > Music, SFX, UI.
GameplaySetup.ConfigurePhysics (layers, Physics.IgnoreLayerCollision, Time and Physics through SerializedObject). GATE: ReadPhysicsSettings in a second process shows the matrix, 0.02 s and the cap (measured: Time.* setters plus SaveAssets did not persist).GameplayScenes.BuildNavArena pattern: surface layerMask = Environment, voxel = radius/3, BuildNavMesh() then AssetDatabase.CreateAsset(surface.navMeshData, ...) as the Inspector Bake button does, save. Build Height Mesh when agents use stairs; NavMesh Modifier Remove Object on foliage; Collect Objects = Volume or Modifier-only to scope. GATE: CalculatePath PathComplete through every door, SamplePosition on spawns and treads, data present after reopening, scene still text; overlay capture opened.FloatingCapsule when it is. Agent locomotion with AgentLocomotionSync: agent drives (root motion off, speed from deltaPosition) or animation drives (updatePosition = false, 0.9 pull beyond the radius). GATE: 0 cc.* audit errors; ControllerTests numbers; drift test.EnemyBrain + EnemyDirector; perception cheapest first, then one ray on an occluder mask with QueryTriggerInteraction.Ignore, batched in LineOfSightBatch (RaycastCommand with QueryParameters) at scale; agent off before obstacle on death. GATE: EnemyLoopTests times Patrol > Chase > Attack > Search > Patrol > Dead.SweepProjectile. NonAlloc through Queries (loop on the count, flag a full buffer, sort when order matters); Physics.SyncTransforms() before querying colliders moved by transform. ProjectilePool with collectionCheck. GATE: CcdLadderMeasured and QueryTests at your numbers; CountActive back to 0.GameplayAudio.CreateCombatMixer or a template; every source routed; CombatAudio capped emitters; sliders on a parameter no snapshot drives; music priority 0; distance muffling with an AudioLowPassFilter curve. GATE: AudioTests, AudioSpatialTests (music band under spam), 0 audio.* errors; a human listening pass at caps 30, 15, 5 under stress, keeping the smallest that sounds full (BgpqoRFCNOs [00:17:23]).BuildCrowdScene at the real count, AgentProfile.PlayModeTimings, AIBudgetMeter, JobWaitMeter; PerceptionBenchmark, ProximityBenchmark, dots_gate and proximity_gate before any DOTS proposal. GATE: p95 AND the worst frame; editor numbers confirmed in a development player with Profile Analyzer and the native device profiler (Survival Kids [00:10:27]; scenario-unity-performance).ut_gameplay.netcode_fit, authority and tick sheet, prediction proven in Edit Mode with NetSim before NGO wiring. GATE: reconciliation tests green; the design says what must be hand-built.| Value | Relative to | Source |
|---|---|---|
| 0.02 s (50 Hz); 1/60 for one step per 60 fps frame | Fixed Timestep | Manual; pTz3LMQpvfA [00:01:22] |
| 0.333 s default (about 16 steps at 50 Hz); 0.1 s = 5 steps | Maximum Allowed Timestep | measured |
| near 10 calls per frame = problem | Physics.Processing Calls | Manual |
| Discrete tunnels above about (thickness + 2r + 0.02) / dt | 50 Hz | discrete_tunnel_speed; measured 20 m/s, 5 cm wall |
| skin >= max(0.01, 0.1 x radius); step 0.1 to 0.4 m; min move 0 | 2 m CharacterController | Manual |
| sag = m x g / k; x2 acceleration on reversals | floating capsule | measured; Toyful [00:05:32] |
| 3 voxels per radius; 4-6 interiors; >8 rarely helps; door >= about 1.5x agent diameter | agent radius | manual; measured |
| drift pull 0.9 x delta when drift > agent radius (measured max 0.41 to 0.45 m at r 0.4, 1.84 m without) | animation-driven agent | AI Navigation manual |
| carve seen next frame; Carve Only Stationary re-carves after 0.5 s still (measured 0.50 to 0.61 s) | NavMesh Obstacle | manual; measured |
| AI slice 0.10-0.15 ms (Update) vs about 0.01 ms (10 Hz director) | 200 agents, Editor | measured |
| Burst parallel slower than managed at 200 agents, faster from 2,000 | perception prefilter | measured |
| brute force 7-8 ns managed, 1.2-1.5 ns Burst per item-query pair; grid 0.3-1.3 ms vs 14-15 ms at 10,000 x 200 | proximity queries | measured (Survival Kids KD tree: 5 ms to 0.08 ms, 20 queries over 1,000 items) |
| 200 ms noticed; FPS < 100 ms; 30 Hz tick; update rate > fire rate | netcode | NGO manual |
| 32 real / 512 virtual voices; priority 0-256, default 128 | Audio settings | measured; manual |
| gain = min/d past Max Distance (Logarithmic); 0 at Max Distance (Linear) | 3D rolloff | measured |
| low-pass cutoff curve 22000 to 10 Hz, needs an Audio Low Pass Filter | distance muffling | Manual; measured 8 kHz at 8 m: 0.03x |
| slider 0.0001..1 -> 20 log10(v); 10-15 instances per frequent sound | mixer, voices | DU7cgVsU2rM [00:14:30]; BgpqoRFCNOs [00:17:56] |
compile_errors == []; settings read back in a new process; AuditGameplayScene 0 errors (the negative control flags every seeded trap); suites green with GAMEPLAY_METRICS parsed; CCD and sweep tests at the real speed; pools back to baseline; crowd CSV at the real count with p95, worst frame and AI slice; code_audit 0 errors.ut_review.image_checks and were opened; controller and locomotion feel judged from frames when feel is the brief.| Mistake | What it looks like | Fix |
|---|---|---|
| Continuous Dynamic on every fast body | CPU grows, still tunnels a dynamic plate | Speculative first; SweepProjectile |
| thin ray for a fat projectile | misses what its radius touches | sweep the collider's shape (Queries.SweepShape) |
| NonAlloc loop over the buffer | stale or silently dropped hits, unordered | loop on the count; flag count == length; sort |
Physics.autoSyncTransforms = true | hidden sync before every query, CS0618 | one Physics.SyncTransforms() before the query |
Time.maximumDeltaTime = x in an editor job | back to 0.333 next launch | SerializedObject on TimeManager.asset |
BuildNavMesh() then save the scene | data embedded, scene file turns binary | AssetDatabase.CreateAsset(surface.navMeshData) first |
| querying after saving over an existing scene | NavMesh empty, paths invalid | GameplayScenes.EnsureLoaded |
| stairs without a HeightMesh | agents glide up a ramp | Build Height Mesh, rebake |
| repath in the frame an obstacle carves | route through the new body | query next frame |
| agent and animation both move the character | foot sliding, jitter | one way: AgentLocomotionSync |
| static singleton, domain reload off | last session's hub, double updates | reset in SubsystemRegistration; SafeUnregister |
TransformAccessArray from FindObjectsByType<Transform> | frame cost grows with the scene | own list, rebuild on change |
| writing TAA transforms while the job runs | main thread stalls for the job | copy out read-only; write after Complete() |
| triggers for "anything near me" at scale | transform sync on every mover | own list, Burst, then grid (proximity_gate) |
| MonoBehaviour in a file with another name | silently absent after a scene save | one MonoBehaviour per file |
PlayClipAtPoint for combat sounds | sliders do nothing | pooled emitters routed to a group |
| low-pass "distance" effect on the SFX group | every sound muffled alike | AudioLowPassFilter curve per source |
| trusting Max Distance to silence a Logarithmic source | still audible far away (1/d) | Linear or custom curve, or cull by distance |
| "NGO has client prediction" in a plan | promised loop does not exist | anticipation plus hand-built reconciliation, or Netcode for Entities |
MixerControl.SetUserVolume); crowd CSVs, AI slice and job waits to scenario-unity-performance; 2D physics to scenario-unity-2d; audio limits to scenario-unity-mobile and scenario-unity-web. Packet: scene, job ids, audit JSON, test metrics, CSV verdicts, Verified and Assumed.linearVelocity, linearDamping, PhysicsMaterial, Physics.simulationMode; Physics.autoSyncTransforms deprecated (not just off); RaycastCommand takes QueryParameters; Physics.BakeMesh(int...) obsolete.Entities.ForEach; 6.6 makes Burst built in and new projects skip domain reload on Play.[Rpc(SendTo.Server)]; override OnUpdate, not NetworkTransform.Update; Multiplayer Services replaces Lobby and Relay.references/expert-notes.md: principles by source, timestamps, measured numbers.references/procedures.md: procedures as code with live tests and results (G1 to G16).references/critique.md: the self-review rubric.references/gui-paths.md: windows and menus for the same procedures.references/sources.md: sources, credentials, timestamps, revision history.scripts/ut_gameplay.py: install, numbers, gates (DOTS, proximity, netcode, AI structure), rolloff model, metrics, code audit.scripts/AgentKit/Gameplay/: editor jobs. scripts/Runtime/: brains, director, hub, queries, sweeps, coupling, Burst jobs, meters, pools, audio, controller, netcode model.