一键导入
idle-clicker
Idle/clicker game architecture — big number math, offline progress, prestige/rebirth, upgrade trees, automation, currency systems, time-based rewards.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Idle/clicker game architecture — big number math, offline progress, prestige/rebirth, upgrade trees, automation, currency systems, time-based rewards.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
DOTween animation library — sequence composition, tween lifecycle, easing, kill strategies. CRITICAL: Always kill tweens in OnDestroy to prevent leaks and errors.
Dialogue tree patterns — ScriptableObject graph, node types (text, choice, condition, event), typewriter effect, localization-ready. Load when implementing NPC conversations.
Generic state machine patterns — IState interface, StateMachine<T>, game state management (menu/gameplay/pause), enemy AI states, hierarchical FSM. Load when implementing state-driven behavior.
2D platformer architecture — tight controls (coyote time, input buffer, variable jump), level design patterns, collectibles, checkpoints, hazards, boss patterns.
Unity physics — non-allocating queries, collision layers, FixedUpdate discipline, continuous collision detection, character controllers, joints.
How the atomic instinct learning system works — observations, distillation, confidence scoring, project vs global scope, and promotion/evolution workflows.
| name | idle-clicker |
| description | Idle/clicker game architecture — big number math, offline progress, prestige/rebirth, upgrade trees, automation, currency systems, time-based rewards. |
| globs | ["**/Idle*.cs","**/Clicker*.cs","**/Currency*.cs","**/Upgrade*.cs","**/Prestige*.cs"] |
Standard float/double loses precision at large values. Use a custom big number or double with formatted display.
public readonly struct BigNumber
{
private readonly double _value;
private readonly int _exponent;
public BigNumber(double value, int exponent = 0)
{
_value = value;
_exponent = exponent;
// Normalize would be called here
}
public static BigNumber operator +(BigNumber a, BigNumber b)
{
if (a._exponent == b._exponent)
{
return new BigNumber(a._value + b._value, a._exponent);
}
int diff = a._exponent - b._exponent;
if (diff > 15) return a; // b is negligible
if (diff < -15) return b;
if (diff > 0)
{
return new BigNumber(a._value + b._value / System.Math.Pow(10, diff), a._exponent);
}
return new BigNumber(b._value + a._value / System.Math.Pow(10, -diff), b._exponent);
}
public string ToFormattedString()
{
// 1.23K, 4.56M, 7.89B, 1.23T, etc.
string[] suffixes = { "", "K", "M", "B", "T", "Qa", "Qi", "Sx", "Sp", "Oc", "No", "Dc" };
int tier = _exponent / 3;
if (tier < suffixes.Length)
{
double displayValue = _value * System.Math.Pow(10, _exponent % 3);
return $"{displayValue:F2}{suffixes[tier]}";
}
return $"{_value:F2}e{_exponent}";
}
}
[CreateAssetMenu(menuName = "Idle/Currency Definition")]
public sealed class CurrencyDefinition : ScriptableObject
{
[SerializeField] private string _currencyId;
[SerializeField] private string _displayName;
[SerializeField] private Sprite _icon;
public string CurrencyId => _currencyId;
public string DisplayName => _displayName;
public Sprite Icon => _icon;
}
public sealed class CurrencyManager : MonoBehaviour
{
private readonly Dictionary<string, double> _currencies = new();
public event System.Action<string, double> OnCurrencyChanged;
public double GetAmount(string currencyId)
{
_currencies.TryGetValue(currencyId, out double amount);
return amount;
}
public bool CanAfford(string currencyId, double cost)
{
return GetAmount(currencyId) >= cost;
}
public void Add(string currencyId, double amount)
{
if (!_currencies.ContainsKey(currencyId))
{
_currencies[currencyId] = 0;
}
_currencies[currencyId] += amount;
OnCurrencyChanged?.Invoke(currencyId, _currencies[currencyId]);
}
public bool Spend(string currencyId, double cost)
{
if (!CanAfford(currencyId, cost)) return false;
_currencies[currencyId] -= cost;
OnCurrencyChanged?.Invoke(currencyId, _currencies[currencyId]);
return true;
}
}
[CreateAssetMenu(menuName = "Idle/Upgrade Definition")]
public sealed class UpgradeDefinition : ScriptableObject
{
[SerializeField] private string _upgradeId;
[SerializeField] private string _displayName;
[SerializeField] private string _currencyId;
[SerializeField] private double _baseCost = 10;
[SerializeField] private float _costMultiplier = 1.15f;
[SerializeField] private int _maxLevel = -1; // -1 = unlimited
[SerializeField] private double _baseEffect = 1;
[SerializeField] private float _effectMultiplier = 1.0f;
public string UpgradeId => _upgradeId;
public string DisplayName => _displayName;
public double GetCost(int currentLevel)
{
return _baseCost * System.Math.Pow(_costMultiplier, currentLevel);
}
public double GetEffect(int currentLevel)
{
return _baseEffect + (_effectMultiplier * currentLevel);
}
public bool IsMaxed(int currentLevel)
{
return _maxLevel >= 0 && currentLevel >= _maxLevel;
}
}
public sealed class OfflineProgressCalculator : MonoBehaviour
{
[SerializeField] private float _offlineEfficiency = 0.5f; // 50% of online rate
[SerializeField] private float _maxOfflineHours = 8f;
private const string LAST_PLAYED_KEY = "LastPlayedTime";
public double CalculateOfflineEarnings(double perSecondRate)
{
string lastPlayed = PlayerPrefs.GetString(LAST_PLAYED_KEY, "");
if (string.IsNullOrEmpty(lastPlayed)) return 0;
long binary = long.Parse(lastPlayed);
System.DateTime lastTime = System.DateTime.FromBinary(binary);
System.TimeSpan elapsed = System.DateTime.UtcNow - lastTime;
double seconds = System.Math.Min(elapsed.TotalSeconds, _maxOfflineHours * 3600);
return perSecondRate * seconds * _offlineEfficiency;
}
public void SaveExitTime()
{
PlayerPrefs.SetString(LAST_PLAYED_KEY, System.DateTime.UtcNow.ToBinary().ToString());
PlayerPrefs.Save();
}
private void OnApplicationPause(bool paused)
{
if (paused) SaveExitTime();
}
private void OnApplicationQuit()
{
SaveExitTime();
}
}
public sealed class PrestigeSystem : MonoBehaviour
{
[SerializeField] private double _prestigeThreshold = 1000000;
[SerializeField] private string _primaryCurrencyId = "gold";
[SerializeField] private string _prestigeCurrencyId = "gems";
[SerializeField] private CurrencyManager _currencyManager;
public int PrestigeCount { get; private set; }
public double CalculatePrestigeReward()
{
double total = _currencyManager.GetAmount(_primaryCurrencyId);
if (total < _prestigeThreshold) return 0;
return System.Math.Floor(System.Math.Sqrt(total / _prestigeThreshold));
}
public bool CanPrestige()
{
return CalculatePrestigeReward() > 0;
}
public void DoPrestige()
{
double reward = CalculatePrestigeReward();
if (reward <= 0) return;
// Award prestige currency
_currencyManager.Add(_prestigeCurrencyId, reward);
PrestigeCount++;
// Reset primary progress
ResetProgress();
}
private void ResetProgress()
{
// Reset primary currency, upgrades, and generators
// Keep prestige currency and prestige upgrades
}
}
Launch → Check offline progress → Show earnings popup
→ Main screen (tap to earn + automated income)
→ Buy upgrades (increase tap/auto income)
→ Prestige when progress slows
→ Restart with permanent bonuses
OnApplicationPause saves state immediately