@musashishao/agent-kit 1.9.0 → 1.9.1
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/.agent/agents/ai-asset-factory.md +700 -0
- package/.agent/agents/ai-audio-factory.md +503 -0
- package/.agent/agents/game-developer.md +4 -4
- package/.agent/agents/orchestrator.md +113 -3
- package/.agent/agents/project-planner.md +67 -0
- package/.agent/agents/unity-mobile-master.md +949 -0
- package/.agent/mcp/config/registry.json +65 -51
- package/.agent/mcp/servers/notebooklm/README.md +114 -0
- package/.agent/mcp/servers/notebooklm/package.json +35 -0
- package/.agent/mcp/servers/notebooklm/src/auth/chrome.ts +225 -0
- package/.agent/mcp/servers/notebooklm/src/auth/index.ts +1 -0
- package/.agent/mcp/servers/notebooklm/src/index.ts +516 -0
- package/.agent/mcp/servers/notebooklm/src/services/index.ts +3 -0
- package/.agent/mcp/servers/notebooklm/src/services/library.ts +217 -0
- package/.agent/mcp/servers/notebooklm/src/services/notebooklm.ts +380 -0
- package/.agent/mcp/servers/notebooklm/tsconfig.json +15 -0
- package/.agent/mcp-gateway/README.md +169 -20
- package/.agent/mcp-gateway/package.json +22 -7
- package/.agent/mcp-gateway/src/auth/index.ts +55 -0
- package/.agent/mcp-gateway/src/auth/middleware.ts +242 -0
- package/.agent/mcp-gateway/src/auth/oauth.ts +462 -0
- package/.agent/mcp-gateway/src/auth/scopes.ts +227 -0
- package/.agent/mcp-gateway/src/index.ts +252 -105
- package/.agent/mcp-gateway/src/observability/index.ts +5 -0
- package/.agent/mcp-gateway/src/observability/otel.ts +405 -0
- package/.agent/mcp-gateway/src/transports/index.ts +5 -0
- package/.agent/mcp-gateway/src/transports/streamableHttp.ts +235 -0
- package/.agent/rules/CODEX.md +89 -0
- package/.agent/rules/CODE_RULES.md +73 -0
- package/.agent/rules/GEMINI.md +25 -0
- package/.agent/rules/MEMORY_STATE.md +110 -0
- package/.agent/rules/REFERENCE.md +33 -141
- package/.agent/rules/REF_SKILLS.md +116 -0
- package/.agent/rules/REF_WORKFLOWS.md +81 -0
- package/.agent/scripts/ak_cli.py +106 -5
- package/.agent/scripts/memory_manager.py +48 -9
- package/.agent/skills/anti-hallucination/SKILL.md +295 -0
- package/.agent/skills/anti-hallucination/scripts/check_hallucination.py +299 -0
- package/.agent/skills/bifurcation-analysis/SKILL.md +56 -0
- package/.agent/skills/brainstorming/SKILL.md +80 -6
- package/.agent/skills/decision-memory/SKILL.md +317 -0
- package/.agent/skills/emergence-detector/SKILL.md +230 -0
- package/.agent/skills/emergence-detector/scripts/check_emergence.py +265 -0
- package/.agent/skills/explained-qa/SKILL.md +142 -0
- package/.agent/skills/explained-qa/game-terminology.md +214 -0
- package/.agent/skills/game-development/ai-dialogue-engine/SKILL.md +442 -0
- package/.agent/skills/game-development/ai-graphics-generator/SKILL.md +463 -0
- package/.agent/skills/game-development/ai-playtest-framework/SKILL.md +570 -0
- package/.agent/skills/game-development/camera-systems/SKILL.md +607 -0
- package/.agent/skills/game-development/card-battle-engine/SKILL.md +618 -0
- package/.agent/skills/game-development/character-controller-3d/SKILL.md +908 -0
- package/.agent/skills/game-development/cloud-save-sync/SKILL.md +527 -0
- package/.agent/skills/game-development/combat-system/SKILL.md +748 -0
- package/.agent/skills/game-development/compliance-rating/SKILL.md +277 -0
- package/.agent/skills/game-development/crossplatform-build/SKILL.md +386 -0
- package/.agent/skills/game-development/cultivation-progression/SKILL.md +520 -0
- package/.agent/skills/game-development/data-driven-balance/SKILL.md +535 -0
- package/.agent/skills/game-development/game-analytics-integrator/SKILL.md +410 -0
- package/.agent/skills/game-development/game-audio-advanced/SKILL.md +646 -0
- package/.agent/skills/game-development/game-economy-designer/SKILL.md +375 -0
- package/.agent/skills/game-development/game-marketing/SKILL.md +85 -0
- package/.agent/skills/game-development/game-state-manager/SKILL.md +883 -0
- package/.agent/skills/game-development/hybrid-game-spec/SKILL.md +220 -0
- package/.agent/skills/game-development/inventory-quest/SKILL.md +747 -0
- package/.agent/skills/game-development/liveops/SKILL.md +308 -0
- package/.agent/skills/game-development/localization/SKILL.md +286 -0
- package/.agent/skills/game-development/mobile-input-patterns/SKILL.md +343 -0
- package/.agent/skills/game-development/monetization-strategy/SKILL.md +94 -0
- package/.agent/skills/game-development/multiplayer-master/SKILL.md +727 -0
- package/.agent/skills/game-development/narrative-branching/SKILL.md +593 -0
- package/.agent/skills/game-development/procedural-level-ai/SKILL.md +367 -0
- package/.agent/skills/game-development/prototyping-rapid/SKILL.md +205 -0
- package/.agent/skills/game-development/spec-ecosystem/SKILL.md +155 -0
- package/.agent/skills/game-development/spec-ecosystem/decision-log-format.md +129 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/PLAN-template.md +178 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/SPEC-template.md +110 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/TASKS-template.md +156 -0
- package/.agent/skills/game-development/survival-systems/SKILL.md +493 -0
- package/.agent/skills/game-development/testing-qa/SKILL.md +270 -0
- package/.agent/skills/game-development/unity-mobile-optimization/SKILL.md +271 -0
- package/.agent/skills/intent-capture/SKILL.md +65 -0
- package/.agent/skills/mcp-composition/SKILL.md +362 -0
- package/.agent/skills/mcp-observability/SKILL.md +323 -0
- package/.agent/skills/mcp-security/SKILL.md +314 -0
- package/.agent/skills/trust-spectrum/SKILL.md +291 -0
- package/.agent/skills/vibe-coding-guard/SKILL.md +328 -0
- package/.agent/templates/AGENTS.game.md +63 -0
- package/.agent/templates/docs/WORKFLOW_GUIDE.en.md +100 -0
- package/.agent/templates/docs/WORKFLOW_GUIDE.vi.md +100 -0
- package/.agent/workflows/ai-agent.md +2 -0
- package/.agent/workflows/autofix.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/context.md +1 -0
- package/.agent/workflows/create.md +39 -8
- package/.agent/workflows/dashboard.md +1 -0
- package/.agent/workflows/debug.md +14 -0
- package/.agent/workflows/deploy.md +14 -0
- package/.agent/workflows/enhance.md +44 -0
- package/.agent/workflows/gamekit-init.md +177 -0
- package/.agent/workflows/gamekit-launch.md +338 -0
- package/.agent/workflows/gamekit-plan.md +204 -0
- package/.agent/workflows/gamekit-qa.md +153 -0
- package/.agent/workflows/gamekit-spec.md +243 -0
- package/.agent/workflows/gamekit-tasks.md +208 -0
- package/.agent/workflows/marketing.md +2 -0
- package/.agent/workflows/next.md +1 -0
- package/.agent/workflows/orchestrate.md +12 -0
- package/.agent/workflows/pentest.md +2 -0
- package/.agent/workflows/plan.md +42 -0
- package/.agent/workflows/preview.md +1 -0
- package/.agent/workflows/quality.md +1 -0
- package/.agent/workflows/saas.md +2 -0
- package/.agent/workflows/spec.md +42 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/test.md +14 -0
- package/.agent/workflows/ui-ux-pro-max.md +1 -0
- package/bin/cli.js +411 -111
- package/package.json +1 -2
- package/.agent/agents/game-asset-curator.md +0 -317
- package/.agent/agents/game-narrative-designer.md +0 -310
- package/.agent/agents/game-qa-agent.md +0 -441
- package/.agent/workflows/game-prototype.md +0 -154
- package/docs/AI_DATA_INFRASTRUCTURE.md +0 -288
- package/docs/CHANGELOG_AI_INFRA.md +0 -141
- package/docs/MIGRATION_GUIDE_V1.9.md +0 -55
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: mobile-input-patterns
|
|
3
|
+
description: Touch input patterns for mobile games. Gestures, virtual joysticks, input abstraction layer, and accessibility considerations.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Bash, Grep, WebSearch
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Mobile Input Patterns Skill
|
|
8
|
+
|
|
9
|
+
> Expert touch input patterns for Unity mobile games.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## When to Use
|
|
14
|
+
|
|
15
|
+
- Implementing touch controls for mobile games
|
|
16
|
+
- Creating virtual joysticks and buttons
|
|
17
|
+
- Gesture recognition (swipe, pinch, tap)
|
|
18
|
+
- Cross-platform input abstraction
|
|
19
|
+
- Accessibility for mobile input
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Input Abstraction Layer
|
|
24
|
+
|
|
25
|
+
### Interface Definition
|
|
26
|
+
```csharp
|
|
27
|
+
public interface IGameInput
|
|
28
|
+
{
|
|
29
|
+
Vector2 Movement { get; }
|
|
30
|
+
Vector2 Aim { get; }
|
|
31
|
+
bool JumpPressed { get; }
|
|
32
|
+
bool ActionPressed { get; }
|
|
33
|
+
|
|
34
|
+
event Action OnJump;
|
|
35
|
+
event Action OnAction;
|
|
36
|
+
event Action<Vector2> OnTap;
|
|
37
|
+
event Action<SwipeDirection> OnSwipe;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
public enum SwipeDirection { Up, Down, Left, Right }
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Mobile Implementation
|
|
44
|
+
```csharp
|
|
45
|
+
public class MobileInput : MonoBehaviour, IGameInput
|
|
46
|
+
{
|
|
47
|
+
[SerializeField] private Joystick _moveJoystick;
|
|
48
|
+
[SerializeField] private Joystick _aimJoystick;
|
|
49
|
+
[SerializeField] private Button _jumpButton;
|
|
50
|
+
|
|
51
|
+
public Vector2 Movement => _moveJoystick.Direction;
|
|
52
|
+
public Vector2 Aim => _aimJoystick.Direction;
|
|
53
|
+
public bool JumpPressed { get; private set; }
|
|
54
|
+
public bool ActionPressed { get; private set; }
|
|
55
|
+
|
|
56
|
+
public event Action OnJump;
|
|
57
|
+
public event Action OnAction;
|
|
58
|
+
public event Action<Vector2> OnTap;
|
|
59
|
+
public event Action<SwipeDirection> OnSwipe;
|
|
60
|
+
|
|
61
|
+
void Awake()
|
|
62
|
+
{
|
|
63
|
+
_jumpButton.onClick.AddListener(() => OnJump?.Invoke());
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Desktop Fallback
|
|
69
|
+
```csharp
|
|
70
|
+
public class DesktopInput : MonoBehaviour, IGameInput
|
|
71
|
+
{
|
|
72
|
+
public Vector2 Movement => new(
|
|
73
|
+
Input.GetAxisRaw("Horizontal"),
|
|
74
|
+
Input.GetAxisRaw("Vertical")
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
public Vector2 Aim => (Input.mousePosition -
|
|
78
|
+
new Vector3(Screen.width/2, Screen.height/2)).normalized;
|
|
79
|
+
|
|
80
|
+
public bool JumpPressed => Input.GetKeyDown(KeyCode.Space);
|
|
81
|
+
public bool ActionPressed => Input.GetMouseButtonDown(0);
|
|
82
|
+
|
|
83
|
+
public event Action OnJump;
|
|
84
|
+
public event Action OnAction;
|
|
85
|
+
public event Action<Vector2> OnTap;
|
|
86
|
+
public event Action<SwipeDirection> OnSwipe;
|
|
87
|
+
|
|
88
|
+
void Update()
|
|
89
|
+
{
|
|
90
|
+
if (Input.GetKeyDown(KeyCode.Space)) OnJump?.Invoke();
|
|
91
|
+
if (Input.GetMouseButtonDown(0)) OnTap?.Invoke(Input.mousePosition);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Gesture Recognition
|
|
99
|
+
|
|
100
|
+
### Tap Detection
|
|
101
|
+
```csharp
|
|
102
|
+
// Single tap, double tap, long press
|
|
103
|
+
public class TapDetector : MonoBehaviour
|
|
104
|
+
{
|
|
105
|
+
[SerializeField] private float _doubleTapTime = 0.3f;
|
|
106
|
+
[SerializeField] private float _longPressTime = 0.5f;
|
|
107
|
+
|
|
108
|
+
private float _lastTapTime;
|
|
109
|
+
private float _touchStartTime;
|
|
110
|
+
|
|
111
|
+
public event Action<Vector2> OnTap;
|
|
112
|
+
public event Action<Vector2> OnDoubleTap;
|
|
113
|
+
public event Action<Vector2> OnLongPress;
|
|
114
|
+
|
|
115
|
+
void Update()
|
|
116
|
+
{
|
|
117
|
+
if (Input.touchCount == 0) return;
|
|
118
|
+
Touch touch = Input.GetTouch(0);
|
|
119
|
+
|
|
120
|
+
switch (touch.phase)
|
|
121
|
+
{
|
|
122
|
+
case TouchPhase.Began:
|
|
123
|
+
_touchStartTime = Time.time;
|
|
124
|
+
break;
|
|
125
|
+
|
|
126
|
+
case TouchPhase.Stationary:
|
|
127
|
+
if (Time.time - _touchStartTime > _longPressTime)
|
|
128
|
+
{
|
|
129
|
+
OnLongPress?.Invoke(touch.position);
|
|
130
|
+
_touchStartTime = float.MaxValue; // Prevent re-trigger
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
|
|
134
|
+
case TouchPhase.Ended:
|
|
135
|
+
if (Time.time - _touchStartTime < _longPressTime)
|
|
136
|
+
{
|
|
137
|
+
if (Time.time - _lastTapTime < _doubleTapTime)
|
|
138
|
+
OnDoubleTap?.Invoke(touch.position);
|
|
139
|
+
else
|
|
140
|
+
OnTap?.Invoke(touch.position);
|
|
141
|
+
|
|
142
|
+
_lastTapTime = Time.time;
|
|
143
|
+
}
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Swipe Detection
|
|
151
|
+
```csharp
|
|
152
|
+
public class SwipeDetector : MonoBehaviour
|
|
153
|
+
{
|
|
154
|
+
[SerializeField] private float _minSwipeDistance = 50f;
|
|
155
|
+
[SerializeField] private float _maxSwipeTime = 0.5f;
|
|
156
|
+
|
|
157
|
+
private Vector2 _startPos;
|
|
158
|
+
private float _startTime;
|
|
159
|
+
|
|
160
|
+
public event Action<SwipeDirection, float> OnSwipe;
|
|
161
|
+
|
|
162
|
+
void Update()
|
|
163
|
+
{
|
|
164
|
+
if (Input.touchCount == 0) return;
|
|
165
|
+
Touch touch = Input.GetTouch(0);
|
|
166
|
+
|
|
167
|
+
switch (touch.phase)
|
|
168
|
+
{
|
|
169
|
+
case TouchPhase.Began:
|
|
170
|
+
_startPos = touch.position;
|
|
171
|
+
_startTime = Time.time;
|
|
172
|
+
break;
|
|
173
|
+
|
|
174
|
+
case TouchPhase.Ended:
|
|
175
|
+
if (Time.time - _startTime > _maxSwipeTime) return;
|
|
176
|
+
|
|
177
|
+
Vector2 delta = touch.position - _startPos;
|
|
178
|
+
if (delta.magnitude < _minSwipeDistance) return;
|
|
179
|
+
|
|
180
|
+
SwipeDirection dir;
|
|
181
|
+
float velocity = delta.magnitude / (Time.time - _startTime);
|
|
182
|
+
|
|
183
|
+
if (Mathf.Abs(delta.x) > Mathf.Abs(delta.y))
|
|
184
|
+
dir = delta.x > 0 ? SwipeDirection.Right : SwipeDirection.Left;
|
|
185
|
+
else
|
|
186
|
+
dir = delta.y > 0 ? SwipeDirection.Up : SwipeDirection.Down;
|
|
187
|
+
|
|
188
|
+
OnSwipe?.Invoke(dir, velocity);
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Pinch (Zoom)
|
|
196
|
+
```csharp
|
|
197
|
+
public class PinchDetector : MonoBehaviour
|
|
198
|
+
{
|
|
199
|
+
public event Action<float> OnPinch; // scale factor
|
|
200
|
+
|
|
201
|
+
private float _initialDistance;
|
|
202
|
+
|
|
203
|
+
void Update()
|
|
204
|
+
{
|
|
205
|
+
if (Input.touchCount != 2) return;
|
|
206
|
+
|
|
207
|
+
Touch t0 = Input.GetTouch(0);
|
|
208
|
+
Touch t1 = Input.GetTouch(1);
|
|
209
|
+
|
|
210
|
+
if (t0.phase == TouchPhase.Began || t1.phase == TouchPhase.Began)
|
|
211
|
+
{
|
|
212
|
+
_initialDistance = Vector2.Distance(t0.position, t1.position);
|
|
213
|
+
}
|
|
214
|
+
else if (t0.phase == TouchPhase.Moved || t1.phase == TouchPhase.Moved)
|
|
215
|
+
{
|
|
216
|
+
float currentDistance = Vector2.Distance(t0.position, t1.position);
|
|
217
|
+
float scale = currentDistance / _initialDistance;
|
|
218
|
+
OnPinch?.Invoke(scale);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## Virtual Joystick
|
|
227
|
+
|
|
228
|
+
```csharp
|
|
229
|
+
public class VirtualJoystick : MonoBehaviour,
|
|
230
|
+
IPointerDownHandler, IDragHandler, IPointerUpHandler
|
|
231
|
+
{
|
|
232
|
+
[SerializeField] private RectTransform _background;
|
|
233
|
+
[SerializeField] private RectTransform _handle;
|
|
234
|
+
[SerializeField] private float _handleRange = 50f;
|
|
235
|
+
[SerializeField] private float _deadZone = 0.15f;
|
|
236
|
+
|
|
237
|
+
private Vector2 _input;
|
|
238
|
+
private Canvas _canvas;
|
|
239
|
+
|
|
240
|
+
public Vector2 Direction => _input.magnitude > _deadZone ? _input : Vector2.zero;
|
|
241
|
+
|
|
242
|
+
void Awake() => _canvas = GetComponentInParent<Canvas>();
|
|
243
|
+
|
|
244
|
+
public void OnPointerDown(PointerEventData eventData)
|
|
245
|
+
{
|
|
246
|
+
OnDrag(eventData);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
public void OnDrag(PointerEventData eventData)
|
|
250
|
+
{
|
|
251
|
+
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
|
252
|
+
_background, eventData.position,
|
|
253
|
+
_canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : _canvas.worldCamera,
|
|
254
|
+
out Vector2 localPos
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
_input = Vector2.ClampMagnitude(localPos / _handleRange, 1f);
|
|
258
|
+
_handle.anchoredPosition = _input * _handleRange;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
public void OnPointerUp(PointerEventData eventData)
|
|
262
|
+
{
|
|
263
|
+
_input = Vector2.zero;
|
|
264
|
+
_handle.anchoredPosition = Vector2.zero;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
---
|
|
270
|
+
|
|
271
|
+
## Accessibility Considerations
|
|
272
|
+
|
|
273
|
+
| Guideline | Implementation |
|
|
274
|
+
|-----------|----------------|
|
|
275
|
+
| **Touch Target Size** | Min 48x48 dp (hardware pixels) |
|
|
276
|
+
| **One-Hand Mode** | Optional UI repositioning |
|
|
277
|
+
| **Haptic Feedback** | `Handheld.Vibrate()` on key actions |
|
|
278
|
+
| **Customizable Controls** | Save joystick positions |
|
|
279
|
+
| **Gesture Alternatives** | Buttons for all gestures |
|
|
280
|
+
|
|
281
|
+
```csharp
|
|
282
|
+
// Haptic feedback
|
|
283
|
+
public static class HapticFeedback
|
|
284
|
+
{
|
|
285
|
+
public static void Light()
|
|
286
|
+
{
|
|
287
|
+
#if UNITY_IOS
|
|
288
|
+
// iOS-specific haptic
|
|
289
|
+
#elif UNITY_ANDROID
|
|
290
|
+
Handheld.Vibrate();
|
|
291
|
+
#endif
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
---
|
|
297
|
+
|
|
298
|
+
## Anti-Patterns
|
|
299
|
+
|
|
300
|
+
| ❌ Don't | ✅ Do |
|
|
301
|
+
|----------|-------|
|
|
302
|
+
| Tiny touch targets | Min 48dp touch areas |
|
|
303
|
+
| Gesture-only controls | Provide button alternatives |
|
|
304
|
+
| Fixed joystick position | Allow customization |
|
|
305
|
+
| No haptic feedback | Add for key actions |
|
|
306
|
+
| Ignore screen notches | Use safe area |
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Safe Area Handling
|
|
311
|
+
|
|
312
|
+
```csharp
|
|
313
|
+
public class SafeAreaHandler : MonoBehaviour
|
|
314
|
+
{
|
|
315
|
+
private RectTransform _panel;
|
|
316
|
+
|
|
317
|
+
void Awake()
|
|
318
|
+
{
|
|
319
|
+
_panel = GetComponent<RectTransform>();
|
|
320
|
+
ApplySafeArea();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
void ApplySafeArea()
|
|
324
|
+
{
|
|
325
|
+
Rect safeArea = Screen.safeArea;
|
|
326
|
+
|
|
327
|
+
Vector2 anchorMin = safeArea.position;
|
|
328
|
+
Vector2 anchorMax = safeArea.position + safeArea.size;
|
|
329
|
+
|
|
330
|
+
anchorMin.x /= Screen.width;
|
|
331
|
+
anchorMin.y /= Screen.height;
|
|
332
|
+
anchorMax.x /= Screen.width;
|
|
333
|
+
anchorMax.y /= Screen.height;
|
|
334
|
+
|
|
335
|
+
_panel.anchorMin = anchorMin;
|
|
336
|
+
_panel.anchorMax = anchorMax;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
> **Remember:** Test on real devices. Emulators don't have thumbs.
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: monetization-strategy
|
|
3
|
+
description: Expertise in game monetization models, IAP, Ads, and economy design.
|
|
4
|
+
allowed-tools: Read, Write, Edit, Glob, Grep
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 💰 Monetization Strategy
|
|
8
|
+
|
|
9
|
+
> **Purpose:** Design and implement sustainable revenue models for games.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. Monetization Models
|
|
14
|
+
|
|
15
|
+
| Model | Description | Best For |
|
|
16
|
+
|-------|-------------|----------|
|
|
17
|
+
| **F2P (Free-to-Play)** | Free access + IAP/Ads | Hypercasual, Mobile RPG, Multiplayer |
|
|
18
|
+
| **Premium** | One-time purchase | Narrative games, PC/Console indies |
|
|
19
|
+
| **Hybrid** | F2P + Subscription (Battle Pass) | Live service games |
|
|
20
|
+
| **P2E (Play-to-Earn)** | Blockchain/Crypto based | Web3 games (Niche) |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 2. In-App Purchases (IAP) Design
|
|
25
|
+
|
|
26
|
+
### Types of Goods
|
|
27
|
+
1. **Consumables:** Currencies (Gold, Gems), Energy, Health potions.
|
|
28
|
+
2. **Non-Consumables:** Remove Ads, Level packs, Cosmetic skins.
|
|
29
|
+
3. **Subscriptions:** Battle Pass, VIP Status (Daily gems).
|
|
30
|
+
|
|
31
|
+
### Implementation Pattern (Unity/Godot)
|
|
32
|
+
- **StoreKit (iOS) / Google Play Billing (Android)**
|
|
33
|
+
- **Wrapper:** Use Unity IAP or Godot's Payment plugins.
|
|
34
|
+
- **Validation:** ALWAYS validate receipts on server-side (prevent hacks).
|
|
35
|
+
|
|
36
|
+
```csharp
|
|
37
|
+
// Unity IAP Example Pattern
|
|
38
|
+
public void OnPurchaseComplete(Product product) {
|
|
39
|
+
if (ValidateReceipt(product.receipt)) {
|
|
40
|
+
UnlockContent(product.definition.id);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## 3. Advertising Strategy
|
|
48
|
+
|
|
49
|
+
### Ad Formats
|
|
50
|
+
1. **Rewarded Video:** User watches ad → Gets reward (Best UX, High eCPM).
|
|
51
|
+
2. **Interstitial:** Full screen between levels (High churn risk if overused).
|
|
52
|
+
3. **Banner:** Static bottom bar (Low revenue, visual noise).
|
|
53
|
+
|
|
54
|
+
### Best Practices
|
|
55
|
+
- **Frequency Capping:** Limit ads to avoid rage-quitting (e.g., max 1 interstitial / 3 mins).
|
|
56
|
+
- **Placement:** "Double Rewards" button at level end is highly effective.
|
|
57
|
+
- **Mediation:** Use AdMob/AppLovin/IronSource mediation to maximize fill rate.
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## 4. Game Economy Design
|
|
62
|
+
|
|
63
|
+
### The Core Loop Interaction
|
|
64
|
+
The economy must act as a distinct layer over the core gameplay loop.
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
Gameplay → Earn Currency → Upgrade/Buy → Better Gameplay
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Sinks & Faucets
|
|
71
|
+
- **Faucet (Inflow):** Daily rewards, Level clear rewards, IAP.
|
|
72
|
+
- **Sink (Outflow):** Upgrades, Consumables, Cosmetics.
|
|
73
|
+
- **Balance:** Faucets must slightly outweigh Sinks initially, then tighten to encourage IAP.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 5. Compliance & Ethics
|
|
78
|
+
|
|
79
|
+
- **Disclosure:** Clearly mark ads and IAP.
|
|
80
|
+
- **Drop Rates:** Must disclose gacha/lootbox probabilities (Legal requirement in many regions).
|
|
81
|
+
- **Dark Patterns:** Avoid accidental purchases or misleading "x" buttons.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Usage Example
|
|
86
|
+
|
|
87
|
+
**User:** "How should I monetize my mobile puzzle game?"
|
|
88
|
+
|
|
89
|
+
**Agent Response:**
|
|
90
|
+
"For a puzzle game, a **Hybrid F2P** model is best:
|
|
91
|
+
1. **Core:** Free to play levels.
|
|
92
|
+
2. **Ads:** Rewarded Video for 'Extra Moves' or 'Hints'.
|
|
93
|
+
3. **IAP:** 'Remove Ads' pack and 'Coin Bundles' for power-ups.
|
|
94
|
+
4. **Strategy:** Do NOT use interstitials until level 10 to ensure retention."
|