@leejungkiin/awkit 1.7.1 → 1.7.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/awk.js +576 -84
- package/core/CLAUDE.md +1 -1
- package/core/GEMINI.md +148 -167
- package/core/GEMINI.md.bak +149 -116
- package/core/skill-runtime-manifest.json +3 -0
- package/docs/Claude Fable 5.md +3826 -0
- package/docs/android_kotlin_system_instruction.md +210 -0
- package/docs/brainstorm_ponytail_integration.md +146 -0
- package/docs/brainstorm_smart_setup.md +113 -0
- package/docs/deep-research-report (1).md +293 -0
- package/docs/history/GEMINI.v1.md +135 -0
- package/docs/history/brainstorm_antigravity_unified_architecture.v1.md +105 -0
- package/docs/history/implementation_plan.v1.md +58 -0
- package/package.json +4 -1
- package/scripts/artifact-storage.js +130 -0
- package/scripts/automation-gate.js +35 -2
- package/scripts/claude-plan.js +76 -0
- package/scripts/dependency-manager.js +210 -0
- package/scripts/exec-rtk.js +11 -5
- package/scripts/i18n-helper.js +381 -0
- package/scripts/multi-model-pipeline.js +144 -0
- package/skill-packs/mobile-ios/pack.json +4 -2
- package/skill-packs/reverse-engineering/pack.json +1 -0
- package/skills/CATALOG.md +20 -0
- package/skills/GEMINI.md +9 -1
- package/skills/TRIGGER_INDEX.md +10 -0
- package/skills/ai-music/SKILL.md +275 -0
- package/skills/android-re-analyzer/SKILL.md +238 -0
- package/skills/android-re-analyzer/references/api-extraction-patterns.md +119 -0
- package/skills/android-re-analyzer/references/call-flow-analysis.md +176 -0
- package/skills/android-re-analyzer/references/fernflower-usage.md +115 -0
- package/skills/android-re-analyzer/references/jadx-usage.md +116 -0
- package/skills/android-re-analyzer/references/setup-guide.md +221 -0
- package/skills/android-re-analyzer/scripts/check-deps.sh +129 -0
- package/skills/android-re-analyzer/scripts/decompile.sh +375 -0
- package/skills/android-re-analyzer/scripts/find-api-calls.sh +118 -0
- package/skills/android-re-analyzer/scripts/install-dep.sh +448 -0
- package/skills/animal-island-ui-style/SKILL.md +1450 -0
- package/skills/app-store-review-agent/SKILL.md +164 -0
- package/skills/app-store-review-agent/references/guidelines/README.md +154 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/ai_apps.md +37 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/all_apps.md +50 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/crypto_finance.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/games.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/health_fitness.md +31 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/kids.md +27 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/macos.md +38 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/social_ugc.md +32 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/subscription_iap.md +34 -0
- package/skills/app-store-review-agent/references/guidelines/by-app-type/vpn.md +18 -0
- package/skills/app-store-review-agent/references/rules/design/minimum_functionality.md +96 -0
- package/skills/app-store-review-agent/references/rules/design/sign_in_with_apple.md +54 -0
- package/skills/app-store-review-agent/references/rules/entitlements/unused_entitlements.md +83 -0
- package/skills/app-store-review-agent/references/rules/metadata/accurate_metadata.md +54 -0
- package/skills/app-store-review-agent/references/rules/metadata/apple_trademark.md +99 -0
- package/skills/app-store-review-agent/references/rules/metadata/china_storefront.md +72 -0
- package/skills/app-store-review-agent/references/rules/metadata/competitor_terms.md +56 -0
- package/skills/app-store-review-agent/references/rules/metadata/subscription_metadata.md +81 -0
- package/skills/app-store-review-agent/references/rules/privacy/privacy_manifest.md +84 -0
- package/skills/app-store-review-agent/references/rules/privacy/unnecessary_data.md +60 -0
- package/skills/app-store-review-agent/references/rules/subscription/misleading_pricing.md +63 -0
- package/skills/app-store-review-agent/references/rules/subscription/missing_tos_pp.md +54 -0
- package/skills/awf-ponytail/SKILL.md +91 -0
- package/skills/awf-ponytail-review/SKILL.md +67 -0
- package/skills/awf-session-restore/SKILL.md +3 -3
- package/skills/brainstorm-agent/SKILL.md +11 -2
- package/skills/brainstorm-agent/templates/brief-template.md +8 -0
- package/skills/claude-planner/SKILL.md +47 -0
- package/skills/code-review/SKILL.md +87 -0
- package/skills/expo-game-development/SKILL.md +163 -0
- package/skills/flutter/LICENSE.txt +202 -0
- package/skills/flutter/SKILL.md +127 -0
- package/skills/flutter-project-creater/LICENSE.txt +202 -0
- package/skills/flutter-project-creater/SKILL.md +106 -0
- package/skills/game-developer/SKILL.md +163 -0
- package/skills/game-developer/references/ecs-patterns.md +501 -0
- package/skills/game-developer/references/multiplayer-networking.md +475 -0
- package/skills/game-developer/references/performance-optimization.md +422 -0
- package/skills/game-developer/references/unity-patterns.md +271 -0
- package/skills/game-developer/references/unreal-cpp.md +352 -0
- package/skills/generate-gui-assets/SKILL.md +305 -0
- package/skills/generate-gui-assets/agents/openai.yaml +4 -0
- package/skills/generate-gui-assets/references/catalog-schema.md +58 -0
- package/skills/generate-gui-assets/references/extraction-techniques.md +21 -0
- package/skills/generate-gui-assets/references/prompt-patterns.md +58 -0
- package/skills/generate-gui-assets/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/generate-gui-assets/scripts/build_gui_contact_sheet.py +51 -0
- package/skills/generate-gui-assets/scripts/clean_chroma_edges.py +262 -0
- package/skills/generate-gui-assets/scripts/copy_approved_icons.py +64 -0
- package/skills/generate-gui-assets/scripts/prepare_gui_asset_run.py +91 -0
- package/skills/generate-gui-assets/scripts/suggest_grid_options.py +63 -0
- package/skills/generate-gui-assets/scripts/validate_gui_catalog.py +50 -0
- package/skills/godot-game-development/SKILL.md +142 -0
- package/skills/hatch-pet/LICENSE.txt +201 -0
- package/skills/hatch-pet/SKILL.md +420 -0
- package/skills/hatch-pet/agents/openai.yaml +4 -0
- package/skills/hatch-pet/references/animation-rows.md +29 -0
- package/skills/hatch-pet/references/codex-pet-contract.md +35 -0
- package/skills/hatch-pet/references/qa-rubric.md +60 -0
- package/skills/hatch-pet/scripts/__pycache__/clean_chroma_edges.cpython-311.pyc +0 -0
- package/skills/hatch-pet/scripts/clean_chroma_edges.py +262 -0
- package/skills/hatch-pet/scripts/compose_atlas.py +150 -0
- package/skills/hatch-pet/scripts/derive_running_left_from_running_right.py +143 -0
- package/skills/hatch-pet/scripts/extract_strip_frames.py +323 -0
- package/skills/hatch-pet/scripts/finalize_pet_run.py +382 -0
- package/skills/hatch-pet/scripts/generate_pet_images.py +287 -0
- package/skills/hatch-pet/scripts/inspect_frames.py +246 -0
- package/skills/hatch-pet/scripts/make_contact_sheet.py +96 -0
- package/skills/hatch-pet/scripts/package_custom_pet.py +108 -0
- package/skills/hatch-pet/scripts/pet_job_status.py +117 -0
- package/skills/hatch-pet/scripts/prepare_pet_run.py +673 -0
- package/skills/hatch-pet/scripts/queue_pet_repairs.py +172 -0
- package/skills/hatch-pet/scripts/record_imagegen_result.py +250 -0
- package/skills/hatch-pet/scripts/render_animation_videos.py +134 -0
- package/skills/hatch-pet/scripts/render_animation_videos.sh +5 -0
- package/skills/hatch-pet/scripts/validate_atlas.py +139 -0
- package/skills/i18n-orchestrator/SKILL.md +37 -0
- package/skills/ios-simulator-skill/SKILL.md +390 -0
- package/skills/ios-simulator-skill/scripts/accessibility_audit.py +300 -0
- package/skills/ios-simulator-skill/scripts/app_launcher.py +326 -0
- package/skills/ios-simulator-skill/scripts/app_state_capture.py +400 -0
- package/skills/ios-simulator-skill/scripts/appearance.py +385 -0
- package/skills/ios-simulator-skill/scripts/build_and_test.py +348 -0
- package/skills/ios-simulator-skill/scripts/clipboard.py +103 -0
- package/skills/ios-simulator-skill/scripts/common/__init__.py +61 -0
- package/skills/ios-simulator-skill/scripts/common/cache_utils.py +289 -0
- package/skills/ios-simulator-skill/scripts/common/device_utils.py +462 -0
- package/skills/ios-simulator-skill/scripts/common/env_config.py +35 -0
- package/skills/ios-simulator-skill/scripts/common/hang_pipeline.py +862 -0
- package/skills/ios-simulator-skill/scripts/common/hang_sessions.py +490 -0
- package/skills/ios-simulator-skill/scripts/common/idb_utils.py +180 -0
- package/skills/ios-simulator-skill/scripts/common/screenshot_utils.py +338 -0
- package/skills/ios-simulator-skill/scripts/container.py +668 -0
- package/skills/ios-simulator-skill/scripts/gesture.py +394 -0
- package/skills/ios-simulator-skill/scripts/hang_watcher.py +1533 -0
- package/skills/ios-simulator-skill/scripts/keyboard.py +391 -0
- package/skills/ios-simulator-skill/scripts/localization_audit.py +483 -0
- package/skills/ios-simulator-skill/scripts/location.py +467 -0
- package/skills/ios-simulator-skill/scripts/log_monitor.py +493 -0
- package/skills/ios-simulator-skill/scripts/model_inspector.py +645 -0
- package/skills/ios-simulator-skill/scripts/navigator.py +461 -0
- package/skills/ios-simulator-skill/scripts/privacy_manager.py +310 -0
- package/skills/ios-simulator-skill/scripts/push_notification.py +240 -0
- package/skills/ios-simulator-skill/scripts/screen_mapper.py +296 -0
- package/skills/ios-simulator-skill/scripts/sim_health_check.sh +245 -0
- package/skills/ios-simulator-skill/scripts/sim_list.py +299 -0
- package/skills/ios-simulator-skill/scripts/simctl_boot.py +312 -0
- package/skills/ios-simulator-skill/scripts/simctl_create.py +316 -0
- package/skills/ios-simulator-skill/scripts/simctl_delete.py +357 -0
- package/skills/ios-simulator-skill/scripts/simctl_erase.py +351 -0
- package/skills/ios-simulator-skill/scripts/simctl_shutdown.py +290 -0
- package/skills/ios-simulator-skill/scripts/simulator_selector.py +375 -0
- package/skills/ios-simulator-skill/scripts/status_bar.py +250 -0
- package/skills/ios-simulator-skill/scripts/test_recorder.py +323 -0
- package/skills/ios-simulator-skill/scripts/visual_diff.py +235 -0
- package/skills/ios-simulator-skill/scripts/xcode/__init__.py +13 -0
- package/skills/ios-simulator-skill/scripts/xcode/builder.py +397 -0
- package/skills/ios-simulator-skill/scripts/xcode/cache.py +204 -0
- package/skills/ios-simulator-skill/scripts/xcode/config.py +178 -0
- package/skills/ios-simulator-skill/scripts/xcode/reporter.py +343 -0
- package/skills/ios-simulator-skill/scripts/xcode/xcresult.py +451 -0
- package/skills/ios-visual-qa-strategist/SKILL.md +111 -0
- package/skills/ios-visual-qa-strategist/agents/openai.yaml +4 -0
- package/skills/ios-visual-qa-strategist/references/ios-tool-selection.md +61 -0
- package/skills/ios-visual-qa-strategist/references/minimal-capture-policy.md +56 -0
- package/skills/ios-visual-qa-strategist/references/visual-reasoning-heuristics.md +53 -0
- package/skills/orchestrator/SKILL.md +0 -20
- package/skills/persistent-storage/SKILL.md +55 -0
- package/skills/short-maker/SKILL.md +23 -0
- package/skills/short-maker/scripts/effects.js +56 -0
- package/skills/short-maker/scripts/shortmaker-bridge.js +332 -0
- package/skills/short-maker/scripts/videomix.js +601 -0
- package/skills/short-maker/templates/hyperframes/cinematic-character.template.html +172 -0
- package/skills/short-maker/templates/hyperframes/index.template.html +194 -0
- package/skills/smali-to-kotlin/SKILL.md +128 -0
- package/skills/smali-to-kotlin/examples/getting-started/tech-stack.md +58 -0
- package/skills/smali-to-kotlin/examples/pipeline/data-ui-parity.md +118 -0
- package/skills/smali-to-kotlin/examples/pipeline/scanner-and-bootstrap.md +106 -0
- package/skills/smali-to-kotlin/library-patterns.md +189 -0
- package/skills/smali-to-kotlin/phase-0-discovery.md +128 -0
- package/skills/smali-to-kotlin/phase-1-architecture.md +166 -0
- package/skills/smali-to-kotlin/phase-2-blueprint-ui.md +347 -0
- package/skills/smali-to-kotlin/phase-2-blueprint.md +228 -0
- package/skills/smali-to-kotlin/phase-3-build.md +248 -0
- package/skills/smali-to-kotlin/phase-3-logic-build.md +268 -0
- package/skills/smali-to-kotlin/smali-reading-guide.md +310 -0
- package/skills/smali-to-kotlin/templates/app-map.md +101 -0
- package/skills/smali-to-kotlin/templates/architecture.md +142 -0
- package/skills/smali-to-kotlin/templates/blueprint.md +145 -0
- package/skills/spec-gate/SKILL.md +6 -2
- package/skills/symphony-enforcer/SKILL.md +8 -0
- package/skills/symphony-enforcer/examples/mindful-stop.md +2 -0
- package/skills/symphony-enforcer/examples/three-phase.md +16 -0
- package/skills/symphony-enforcer/examples/trigger-points.md +7 -1
- package/skills/unity-game-development/SKILL.md +231 -0
- package/skills/video-edit/SKILL.md +36 -0
- package/skills/video-edit/scripts/video_edit.py +324 -0
- package/templates/project-identity/android.json +2 -2
- package/templates/project-identity/backend-nestjs.json +2 -2
- package/templates/project-identity/expo.json +2 -2
- package/templates/project-identity/ios.json +2 -2
- package/templates/project-identity/web-nextjs.json +2 -2
- package/templates/setup-mapping.json +48 -0
- package/templates/specs/design-template.md +161 -71
- package/templates/specs/requirements-template.md +65 -133
- package/templates/specs/task-spec-template.xml +3 -0
- package/workflows/_uncategorized/critic.md +40 -0
- package/workflows/_uncategorized/git-rebase-flow.md +81 -0
- package/workflows/_uncategorized/image-gen.md +118 -0
- package/workflows/_uncategorized/multi-model-pipeline.md +60 -0
- package/workflows/_uncategorized/pixel-gen.md +86 -0
- package/workflows/_uncategorized/pixel-setup.md +90 -0
- package/workflows/_uncategorized/ponytail-review.md +59 -0
- package/workflows/_uncategorized/reverse-android-build.md +222 -0
- package/workflows/_uncategorized/reverse-android-design.md +139 -0
- package/workflows/_uncategorized/reverse-android-discover.md +150 -0
- package/workflows/_uncategorized/reverse-android-scan.md +158 -0
- package/workflows/_uncategorized/reverse-android.md +143 -0
- package/workflows/_uncategorized/reverse-ios-build.md +240 -0
- package/workflows/_uncategorized/reverse-ios-design.md +112 -0
- package/workflows/_uncategorized/reverse-ios-discover.md +120 -0
- package/workflows/_uncategorized/reverse-ios-scan.md +155 -0
- package/workflows/_uncategorized/reverse-ios.md +152 -0
- package/workflows/_uncategorized/safety-router.md +34 -0
- package/workflows/_uncategorized/teach.md +89 -0
- package/workflows/_uncategorized/verify-ui.md +53 -0
- package/workflows/_uncategorized/visualize-screenshots.md +34 -0
- package/workflows/ads/ads-analyst.md +201 -0
- package/workflows/ads/ads-audit.md +106 -0
- package/workflows/ads/ads-optimize.md +97 -0
- package/workflows/ads/ads-targeting.md +241 -0
- package/workflows/ads/adsExpert.md +160 -0
- package/workflows/ads/smali-ads-config.md +400 -0
- package/workflows/ads/smali-ads-flow.md +331 -0
- package/workflows/ads/smali-ads-interstitial.md +377 -0
- package/workflows/ads/smali-ads-native.md +382 -0
- package/workflows/context/teach.md +89 -0
- package/workflows/gitnexus.md +8 -8
- package/workflows/lifecycle/brainstorm.md +43 -0
- package/workflows/lifecycle/code.md +5 -0
- package/workflows/lifecycle/init.md +23 -5
- package/workflows/lifecycle/multi-model-pipeline.md +60 -0
- package/workflows/quality/ponytail-review.md +59 -0
- package/workflows/roles/critic.md +40 -0
- package/workflows/roles/safety-router.md +34 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# Performance Optimization
|
|
2
|
+
|
|
3
|
+
## Profiling First
|
|
4
|
+
|
|
5
|
+
```csharp
|
|
6
|
+
using UnityEngine.Profiling;
|
|
7
|
+
|
|
8
|
+
public class PerformanceMonitor : MonoBehaviour
|
|
9
|
+
{
|
|
10
|
+
private void Update()
|
|
11
|
+
{
|
|
12
|
+
// CPU profiling
|
|
13
|
+
Profiler.BeginSample("Enemy AI Update");
|
|
14
|
+
UpdateEnemyAI();
|
|
15
|
+
Profiler.EndSample();
|
|
16
|
+
|
|
17
|
+
// Memory profiling
|
|
18
|
+
long allocatedMemory = Profiler.GetTotalAllocatedMemoryLong();
|
|
19
|
+
long reservedMemory = Profiler.GetTotalReservedMemoryLong();
|
|
20
|
+
|
|
21
|
+
// FPS calculation
|
|
22
|
+
float fps = 1.0f / Time.unscaledDeltaTime;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Memory Optimization
|
|
28
|
+
|
|
29
|
+
```csharp
|
|
30
|
+
// BAD: Allocates garbage every frame
|
|
31
|
+
void Update()
|
|
32
|
+
{
|
|
33
|
+
string status = "Health: " + health + " / " + maxHealth; // Boxing + allocation
|
|
34
|
+
Vector3 direction = transform.position - target.position; // Allocation
|
|
35
|
+
var enemies = GameObject.FindGameObjectsWithTag("Enemy"); // Allocation
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// GOOD: Zero allocations
|
|
39
|
+
private StringBuilder statusBuilder = new StringBuilder(50);
|
|
40
|
+
private Vector3 directionCache;
|
|
41
|
+
private List<Enemy> enemyCache = new List<Enemy>(100);
|
|
42
|
+
|
|
43
|
+
void Update()
|
|
44
|
+
{
|
|
45
|
+
// Reuse StringBuilder
|
|
46
|
+
statusBuilder.Clear();
|
|
47
|
+
statusBuilder.Append("Health: ").Append(health).Append(" / ").Append(maxHealth);
|
|
48
|
+
|
|
49
|
+
// Reuse Vector3
|
|
50
|
+
directionCache = transform.position - target.position;
|
|
51
|
+
|
|
52
|
+
// Cache references (done in Start)
|
|
53
|
+
foreach (var enemy in enemyCache)
|
|
54
|
+
{
|
|
55
|
+
enemy.UpdateLogic();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Draw Call Batching
|
|
61
|
+
|
|
62
|
+
```csharp
|
|
63
|
+
// Static batching (for non-moving objects)
|
|
64
|
+
public class StaticBatchHelper : MonoBehaviour
|
|
65
|
+
{
|
|
66
|
+
void Start()
|
|
67
|
+
{
|
|
68
|
+
// Mark objects as static in Inspector OR
|
|
69
|
+
GameObject[] staticObjects = GameObject.FindGameObjectsWithTag("StaticProp");
|
|
70
|
+
StaticBatchingUtility.Combine(staticObjects, gameObject);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Dynamic batching requirements:
|
|
75
|
+
// - Same material
|
|
76
|
+
// - Vertex count < 300
|
|
77
|
+
// - Same scale (non-uniform scale breaks batching)
|
|
78
|
+
// - No lightmaps
|
|
79
|
+
|
|
80
|
+
// GPU Instancing (for many identical objects)
|
|
81
|
+
// Add to shader: #pragma multi_compile_instancing
|
|
82
|
+
// Add to material: Enable GPU Instancing checkbox
|
|
83
|
+
// Use Graphics.DrawMeshInstanced or Graphics.RenderMeshInstanced
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## LOD (Level of Detail) System
|
|
87
|
+
|
|
88
|
+
```csharp
|
|
89
|
+
using UnityEngine;
|
|
90
|
+
|
|
91
|
+
public class LODSetup : MonoBehaviour
|
|
92
|
+
{
|
|
93
|
+
void SetupLOD()
|
|
94
|
+
{
|
|
95
|
+
LODGroup lodGroup = gameObject.AddComponent<LODGroup>();
|
|
96
|
+
|
|
97
|
+
// LOD 0: 0% - 60% screen height (high detail)
|
|
98
|
+
LOD[] lods = new LOD[3];
|
|
99
|
+
lods[0] = new LOD(0.6f, GetRenderers("LOD0"));
|
|
100
|
+
|
|
101
|
+
// LOD 1: 60% - 30% screen height (medium detail)
|
|
102
|
+
lods[1] = new LOD(0.3f, GetRenderers("LOD1"));
|
|
103
|
+
|
|
104
|
+
// LOD 2: 30% - 10% screen height (low detail)
|
|
105
|
+
lods[2] = new LOD(0.1f, GetRenderers("LOD2"));
|
|
106
|
+
|
|
107
|
+
lodGroup.SetLODs(lods);
|
|
108
|
+
lodGroup.RecalculateBounds();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private Renderer[] GetRenderers(string lodName)
|
|
112
|
+
{
|
|
113
|
+
// Return renderers for specific LOD level
|
|
114
|
+
return transform.Find(lodName).GetComponentsInChildren<Renderer>();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Occlusion Culling
|
|
120
|
+
|
|
121
|
+
```csharp
|
|
122
|
+
// Setup in Unity:
|
|
123
|
+
// 1. Mark static objects as "Occluder Static" and "Occludee Static"
|
|
124
|
+
// 2. Window > Rendering > Occlusion Culling
|
|
125
|
+
// 3. Bake occlusion data
|
|
126
|
+
|
|
127
|
+
// Runtime check
|
|
128
|
+
public class OcclusionCheck : MonoBehaviour
|
|
129
|
+
{
|
|
130
|
+
private Camera mainCamera;
|
|
131
|
+
|
|
132
|
+
void Start()
|
|
133
|
+
{
|
|
134
|
+
mainCamera = Camera.main;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
void Update()
|
|
138
|
+
{
|
|
139
|
+
// Check if object is visible to camera
|
|
140
|
+
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(mainCamera);
|
|
141
|
+
Bounds bounds = GetComponent<Renderer>().bounds;
|
|
142
|
+
|
|
143
|
+
if (GeometryUtility.TestPlanesAABB(planes, bounds))
|
|
144
|
+
{
|
|
145
|
+
// Object is in camera frustum
|
|
146
|
+
UpdateVisibleObject();
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Object Pooling (Performance-Focused)
|
|
153
|
+
|
|
154
|
+
```csharp
|
|
155
|
+
public class OptimizedPool<T> where T : Component
|
|
156
|
+
{
|
|
157
|
+
private readonly Stack<T> available = new Stack<T>();
|
|
158
|
+
private readonly HashSet<T> inUse = new HashSet<T>();
|
|
159
|
+
private readonly T prefab;
|
|
160
|
+
private readonly Transform parent;
|
|
161
|
+
|
|
162
|
+
public OptimizedPool(T prefab, int initialSize, Transform parent = null)
|
|
163
|
+
{
|
|
164
|
+
this.prefab = prefab;
|
|
165
|
+
this.parent = parent;
|
|
166
|
+
|
|
167
|
+
// Pre-warm pool
|
|
168
|
+
for (int i = 0; i < initialSize; i++)
|
|
169
|
+
{
|
|
170
|
+
T instance = Object.Instantiate(prefab, parent);
|
|
171
|
+
instance.gameObject.SetActive(false);
|
|
172
|
+
available.Push(instance);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
public T Get()
|
|
177
|
+
{
|
|
178
|
+
T instance;
|
|
179
|
+
|
|
180
|
+
if (available.Count > 0)
|
|
181
|
+
{
|
|
182
|
+
instance = available.Pop();
|
|
183
|
+
}
|
|
184
|
+
else
|
|
185
|
+
{
|
|
186
|
+
// Pool exhausted, create new
|
|
187
|
+
instance = Object.Instantiate(prefab, parent);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
instance.gameObject.SetActive(true);
|
|
191
|
+
inUse.Add(instance);
|
|
192
|
+
return instance;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
public void Return(T instance)
|
|
196
|
+
{
|
|
197
|
+
if (inUse.Remove(instance))
|
|
198
|
+
{
|
|
199
|
+
instance.gameObject.SetActive(false);
|
|
200
|
+
available.Push(instance);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
public void Clear()
|
|
205
|
+
{
|
|
206
|
+
foreach (var instance in inUse)
|
|
207
|
+
Object.Destroy(instance.gameObject);
|
|
208
|
+
|
|
209
|
+
foreach (var instance in available)
|
|
210
|
+
Object.Destroy(instance.gameObject);
|
|
211
|
+
|
|
212
|
+
inUse.Clear();
|
|
213
|
+
available.Clear();
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Physics Optimization
|
|
219
|
+
|
|
220
|
+
```csharp
|
|
221
|
+
public class PhysicsOptimization : MonoBehaviour
|
|
222
|
+
{
|
|
223
|
+
void Start()
|
|
224
|
+
{
|
|
225
|
+
// Use layers for collision filtering
|
|
226
|
+
// Edit > Project Settings > Physics > Layer Collision Matrix
|
|
227
|
+
|
|
228
|
+
// Use trigger colliders when possible (cheaper than collision)
|
|
229
|
+
// Use simple collider shapes (sphere, box > capsule > mesh)
|
|
230
|
+
|
|
231
|
+
// Disable unnecessary physics
|
|
232
|
+
Rigidbody rb = GetComponent<Rigidbody>();
|
|
233
|
+
rb.sleepThreshold = 0.1f; // Allow sleeping
|
|
234
|
+
rb.interpolation = RigidbodyInterpolation.None; // Only if needed
|
|
235
|
+
|
|
236
|
+
// Use fixed timestep wisely
|
|
237
|
+
// Edit > Project Settings > Time > Fixed Timestep (default 0.02 = 50 fps)
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Raycasts: cache and limit
|
|
241
|
+
private RaycastHit hitInfo;
|
|
242
|
+
private float raycastInterval = 0.1f;
|
|
243
|
+
private float nextRaycast;
|
|
244
|
+
|
|
245
|
+
void Update()
|
|
246
|
+
{
|
|
247
|
+
if (Time.time >= nextRaycast)
|
|
248
|
+
{
|
|
249
|
+
// Use layers to filter raycasts
|
|
250
|
+
int layerMask = 1 << LayerMask.NameToLayer("Ground");
|
|
251
|
+
|
|
252
|
+
if (Physics.Raycast(transform.position, Vector3.down, out hitInfo, 10f, layerMask))
|
|
253
|
+
{
|
|
254
|
+
// Process hit
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
nextRaycast = Time.time + raycastInterval;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Texture and Material Optimization
|
|
264
|
+
|
|
265
|
+
```csharp
|
|
266
|
+
// Texture atlasing
|
|
267
|
+
public class TextureAtlas : MonoBehaviour
|
|
268
|
+
{
|
|
269
|
+
// Combine multiple textures into one atlas
|
|
270
|
+
// Reduces draw calls significantly
|
|
271
|
+
// Use Sprite Atlas or Texture Packer
|
|
272
|
+
|
|
273
|
+
void PackTextures()
|
|
274
|
+
{
|
|
275
|
+
Texture2D[] textures = new Texture2D[10]; // Your textures
|
|
276
|
+
Texture2D atlas = new Texture2D(2048, 2048);
|
|
277
|
+
|
|
278
|
+
// Pack textures into atlas
|
|
279
|
+
Rect[] uvs = atlas.PackTextures(textures, 2, 2048);
|
|
280
|
+
|
|
281
|
+
// Update UV coordinates on meshes
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Material sharing
|
|
286
|
+
public class MaterialSharing : MonoBehaviour
|
|
287
|
+
{
|
|
288
|
+
void Start()
|
|
289
|
+
{
|
|
290
|
+
// BAD: Creates material instance
|
|
291
|
+
Renderer renderer = GetComponent<Renderer>();
|
|
292
|
+
renderer.material.color = Color.red; // Breaks batching!
|
|
293
|
+
|
|
294
|
+
// GOOD: Share material
|
|
295
|
+
Material sharedMat = renderer.sharedMaterial;
|
|
296
|
+
// Modify material asset directly (affects all instances)
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
## Update Optimization
|
|
302
|
+
|
|
303
|
+
```csharp
|
|
304
|
+
// Stagger updates to reduce per-frame cost
|
|
305
|
+
public class StaggeredUpdate : MonoBehaviour
|
|
306
|
+
{
|
|
307
|
+
private static int updateOffset = 0;
|
|
308
|
+
private int myOffset;
|
|
309
|
+
|
|
310
|
+
void Start()
|
|
311
|
+
{
|
|
312
|
+
myOffset = updateOffset++;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
void Update()
|
|
316
|
+
{
|
|
317
|
+
// Only update every 5th frame, staggered
|
|
318
|
+
if ((Time.frameCount + myOffset) % 5 == 0)
|
|
319
|
+
{
|
|
320
|
+
ExpensiveUpdate();
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
void ExpensiveUpdate()
|
|
325
|
+
{
|
|
326
|
+
// AI logic, pathfinding, etc.
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// Distance-based update rates
|
|
331
|
+
public class DistanceBasedUpdate : MonoBehaviour
|
|
332
|
+
{
|
|
333
|
+
private Transform player;
|
|
334
|
+
private float updateInterval;
|
|
335
|
+
private float nextUpdate;
|
|
336
|
+
|
|
337
|
+
void Update()
|
|
338
|
+
{
|
|
339
|
+
if (Time.time < nextUpdate) return;
|
|
340
|
+
|
|
341
|
+
float distance = Vector3.Distance(transform.position, player.position);
|
|
342
|
+
|
|
343
|
+
// Update more frequently when close
|
|
344
|
+
if (distance < 10f)
|
|
345
|
+
updateInterval = 0.05f; // 20 fps
|
|
346
|
+
else if (distance < 50f)
|
|
347
|
+
updateInterval = 0.1f; // 10 fps
|
|
348
|
+
else
|
|
349
|
+
updateInterval = 0.5f; // 2 fps
|
|
350
|
+
|
|
351
|
+
PerformUpdate();
|
|
352
|
+
nextUpdate = Time.time + updateInterval;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
## Async Loading
|
|
358
|
+
|
|
359
|
+
```csharp
|
|
360
|
+
using UnityEngine.SceneManagement;
|
|
361
|
+
using System.Collections;
|
|
362
|
+
|
|
363
|
+
public class AsyncLoader : MonoBehaviour
|
|
364
|
+
{
|
|
365
|
+
public IEnumerator LoadSceneAsync(string sceneName)
|
|
366
|
+
{
|
|
367
|
+
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneName);
|
|
368
|
+
asyncLoad.allowSceneActivation = false;
|
|
369
|
+
|
|
370
|
+
while (!asyncLoad.isDone)
|
|
371
|
+
{
|
|
372
|
+
// Loading progress
|
|
373
|
+
float progress = Mathf.Clamp01(asyncLoad.progress / 0.9f);
|
|
374
|
+
|
|
375
|
+
// When ready, activate
|
|
376
|
+
if (asyncLoad.progress >= 0.9f)
|
|
377
|
+
{
|
|
378
|
+
// Wait for player input or fade completion
|
|
379
|
+
yield return new WaitForSeconds(1f);
|
|
380
|
+
asyncLoad.allowSceneActivation = true;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
yield return null;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
public IEnumerator LoadAssetAsync<T>(string path) where T : Object
|
|
388
|
+
{
|
|
389
|
+
ResourceRequest request = Resources.LoadAsync<T>(path);
|
|
390
|
+
|
|
391
|
+
while (!request.isDone)
|
|
392
|
+
{
|
|
393
|
+
yield return null;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
T asset = request.asset as T;
|
|
397
|
+
// Use asset
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
## Performance Checklist
|
|
403
|
+
|
|
404
|
+
**Target: 60 FPS (16.67ms per frame)**
|
|
405
|
+
|
|
406
|
+
CPU Budget:
|
|
407
|
+
- Game logic: 5-7ms
|
|
408
|
+
- Rendering: 3-5ms
|
|
409
|
+
- Physics: 2-3ms
|
|
410
|
+
- Scripts: 2-3ms
|
|
411
|
+
|
|
412
|
+
Optimization priorities:
|
|
413
|
+
1. Profile first (Profiler, Frame Debugger)
|
|
414
|
+
2. Reduce draw calls (batching, instancing)
|
|
415
|
+
3. Optimize expensive Update loops
|
|
416
|
+
4. Use object pooling
|
|
417
|
+
5. Implement LOD systems
|
|
418
|
+
6. Enable occlusion culling
|
|
419
|
+
7. Optimize texture sizes and compression
|
|
420
|
+
8. Minimize garbage collection (allocations)
|
|
421
|
+
9. Use async loading
|
|
422
|
+
10. Implement distance-based update rates
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
# Unity Development Patterns
|
|
2
|
+
|
|
3
|
+
## MonoBehaviour Best Practices
|
|
4
|
+
|
|
5
|
+
```csharp
|
|
6
|
+
using UnityEngine;
|
|
7
|
+
using System.Collections.Generic;
|
|
8
|
+
|
|
9
|
+
public class EnemyController : MonoBehaviour
|
|
10
|
+
{
|
|
11
|
+
// Serialize private fields for Inspector
|
|
12
|
+
[SerializeField] private float moveSpeed = 5f;
|
|
13
|
+
[SerializeField] private Transform target;
|
|
14
|
+
|
|
15
|
+
// Cache component references
|
|
16
|
+
private Rigidbody rb;
|
|
17
|
+
private Animator animator;
|
|
18
|
+
|
|
19
|
+
private void Awake()
|
|
20
|
+
{
|
|
21
|
+
// Cache components in Awake
|
|
22
|
+
rb = GetComponent<Rigidbody>();
|
|
23
|
+
animator = GetComponent<Animator>();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private void Start()
|
|
27
|
+
{
|
|
28
|
+
// Initialize after all Awake calls complete
|
|
29
|
+
if (target == null)
|
|
30
|
+
target = GameObject.FindGameObjectWithTag("Player").transform;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
private void FixedUpdate()
|
|
34
|
+
{
|
|
35
|
+
// Physics calculations in FixedUpdate
|
|
36
|
+
Vector3 direction = (target.position - transform.position).normalized;
|
|
37
|
+
rb.MovePosition(transform.position + direction * moveSpeed * Time.fixedDeltaTime);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private void OnDisable()
|
|
41
|
+
{
|
|
42
|
+
// Clean up when disabled
|
|
43
|
+
StopAllCoroutines();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## ScriptableObjects for Data
|
|
49
|
+
|
|
50
|
+
```csharp
|
|
51
|
+
[CreateAssetMenu(fileName = "WeaponData", menuName = "Game/Weapon")]
|
|
52
|
+
public class WeaponData : ScriptableObject
|
|
53
|
+
{
|
|
54
|
+
public string weaponName;
|
|
55
|
+
public int damage;
|
|
56
|
+
public float fireRate;
|
|
57
|
+
public GameObject projectilePrefab;
|
|
58
|
+
public AudioClip fireSound;
|
|
59
|
+
|
|
60
|
+
// Methods can contain logic
|
|
61
|
+
public float GetDamageMultiplier(float distance)
|
|
62
|
+
{
|
|
63
|
+
return Mathf.Max(0.5f, 1f - (distance / 100f));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Usage in MonoBehaviour
|
|
68
|
+
public class Weapon : MonoBehaviour
|
|
69
|
+
{
|
|
70
|
+
[SerializeField] private WeaponData weaponData;
|
|
71
|
+
private float nextFireTime;
|
|
72
|
+
|
|
73
|
+
public void Fire()
|
|
74
|
+
{
|
|
75
|
+
if (Time.time < nextFireTime) return;
|
|
76
|
+
|
|
77
|
+
// Use data from ScriptableObject
|
|
78
|
+
Instantiate(weaponData.projectilePrefab, transform.position, transform.rotation);
|
|
79
|
+
nextFireTime = Time.time + 1f / weaponData.fireRate;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Object Pooling Pattern
|
|
85
|
+
|
|
86
|
+
```csharp
|
|
87
|
+
public class ObjectPool : MonoBehaviour
|
|
88
|
+
{
|
|
89
|
+
[SerializeField] private GameObject prefab;
|
|
90
|
+
[SerializeField] private int poolSize = 20;
|
|
91
|
+
|
|
92
|
+
private Queue<GameObject> pool = new Queue<GameObject>();
|
|
93
|
+
|
|
94
|
+
private void Start()
|
|
95
|
+
{
|
|
96
|
+
// Pre-instantiate objects
|
|
97
|
+
for (int i = 0; i < poolSize; i++)
|
|
98
|
+
{
|
|
99
|
+
GameObject obj = Instantiate(prefab);
|
|
100
|
+
obj.SetActive(false);
|
|
101
|
+
pool.Enqueue(obj);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
public GameObject Get()
|
|
106
|
+
{
|
|
107
|
+
if (pool.Count > 0)
|
|
108
|
+
{
|
|
109
|
+
GameObject obj = pool.Dequeue();
|
|
110
|
+
obj.SetActive(true);
|
|
111
|
+
return obj;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Expand pool if needed
|
|
115
|
+
return Instantiate(prefab);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public void Return(GameObject obj)
|
|
119
|
+
{
|
|
120
|
+
obj.SetActive(false);
|
|
121
|
+
pool.Enqueue(obj);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Pooled object example
|
|
126
|
+
public class Bullet : MonoBehaviour
|
|
127
|
+
{
|
|
128
|
+
private ObjectPool pool;
|
|
129
|
+
|
|
130
|
+
public void Initialize(ObjectPool pool)
|
|
131
|
+
{
|
|
132
|
+
this.pool = pool;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private void OnCollisionEnter(Collision collision)
|
|
136
|
+
{
|
|
137
|
+
// Return to pool instead of destroying
|
|
138
|
+
pool.Return(gameObject);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Event System Pattern
|
|
144
|
+
|
|
145
|
+
```csharp
|
|
146
|
+
using System;
|
|
147
|
+
using UnityEngine.Events;
|
|
148
|
+
|
|
149
|
+
// Event definition
|
|
150
|
+
[Serializable]
|
|
151
|
+
public class HealthChangedEvent : UnityEvent<int, int> { } // current, max
|
|
152
|
+
|
|
153
|
+
public class Health : MonoBehaviour
|
|
154
|
+
{
|
|
155
|
+
[SerializeField] private int maxHealth = 100;
|
|
156
|
+
private int currentHealth;
|
|
157
|
+
|
|
158
|
+
// UnityEvent visible in Inspector
|
|
159
|
+
public HealthChangedEvent onHealthChanged;
|
|
160
|
+
public UnityEvent onDeath;
|
|
161
|
+
|
|
162
|
+
private void Start()
|
|
163
|
+
{
|
|
164
|
+
currentHealth = maxHealth;
|
|
165
|
+
onHealthChanged?.Invoke(currentHealth, maxHealth);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
public void TakeDamage(int damage)
|
|
169
|
+
{
|
|
170
|
+
currentHealth = Mathf.Max(0, currentHealth - damage);
|
|
171
|
+
onHealthChanged?.Invoke(currentHealth, maxHealth);
|
|
172
|
+
|
|
173
|
+
if (currentHealth <= 0)
|
|
174
|
+
onDeath?.Invoke();
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// C# event alternative for performance
|
|
179
|
+
public static class GameEvents
|
|
180
|
+
{
|
|
181
|
+
public static event Action<int> OnScoreChanged;
|
|
182
|
+
public static event Action<string> OnGameOver;
|
|
183
|
+
|
|
184
|
+
public static void TriggerScoreChanged(int score) => OnScoreChanged?.Invoke(score);
|
|
185
|
+
public static void TriggerGameOver(string reason) => OnGameOver?.Invoke(reason);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Coroutines Best Practices
|
|
190
|
+
|
|
191
|
+
```csharp
|
|
192
|
+
using System.Collections;
|
|
193
|
+
|
|
194
|
+
public class TimedAbility : MonoBehaviour
|
|
195
|
+
{
|
|
196
|
+
// Cache WaitForSeconds to avoid GC
|
|
197
|
+
private WaitForSeconds cooldownWait = new WaitForSeconds(5f);
|
|
198
|
+
private Coroutine currentAbility;
|
|
199
|
+
|
|
200
|
+
public void ActivateAbility()
|
|
201
|
+
{
|
|
202
|
+
// Stop previous coroutine if running
|
|
203
|
+
if (currentAbility != null)
|
|
204
|
+
StopCoroutine(currentAbility);
|
|
205
|
+
|
|
206
|
+
currentAbility = StartCoroutine(AbilityCoroutine());
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private IEnumerator AbilityCoroutine()
|
|
210
|
+
{
|
|
211
|
+
// Activate ability
|
|
212
|
+
Debug.Log("Ability activated");
|
|
213
|
+
|
|
214
|
+
// Wait for duration
|
|
215
|
+
yield return cooldownWait;
|
|
216
|
+
|
|
217
|
+
// Cooldown complete
|
|
218
|
+
Debug.Log("Ability ready");
|
|
219
|
+
currentAbility = null;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Animation-based coroutine
|
|
223
|
+
private IEnumerator LerpPosition(Vector3 target, float duration)
|
|
224
|
+
{
|
|
225
|
+
Vector3 start = transform.position;
|
|
226
|
+
float elapsed = 0f;
|
|
227
|
+
|
|
228
|
+
while (elapsed < duration)
|
|
229
|
+
{
|
|
230
|
+
elapsed += Time.deltaTime;
|
|
231
|
+
float t = elapsed / duration;
|
|
232
|
+
transform.position = Vector3.Lerp(start, target, t);
|
|
233
|
+
yield return null; // Wait one frame
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
transform.position = target; // Ensure exact final position
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Singleton Pattern (Use Sparingly)
|
|
242
|
+
|
|
243
|
+
```csharp
|
|
244
|
+
public class GameManager : MonoBehaviour
|
|
245
|
+
{
|
|
246
|
+
private static GameManager instance;
|
|
247
|
+
public static GameManager Instance => instance;
|
|
248
|
+
|
|
249
|
+
private void Awake()
|
|
250
|
+
{
|
|
251
|
+
if (instance != null && instance != this)
|
|
252
|
+
{
|
|
253
|
+
Destroy(gameObject);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
instance = this;
|
|
258
|
+
DontDestroyOnLoad(gameObject);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## Performance Tips
|
|
264
|
+
|
|
265
|
+
- Cache `GetComponent<T>()` calls in Awake/Start
|
|
266
|
+
- Use `CompareTag()` instead of `tag == "TagName"`
|
|
267
|
+
- Use object pooling for frequently instantiated objects
|
|
268
|
+
- Avoid `Camera.main` in Update (cache the reference)
|
|
269
|
+
- Use `FixedUpdate` for physics, `Update` for input/logic
|
|
270
|
+
- Disable components instead of GameObjects when possible
|
|
271
|
+
- Use `StringBuilder` for string concatenation in loops
|