重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
godot-genre-simulation by thedivergentai/gd-agentic-skills
npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-simulation优化、系统掌控和令人满足的反馈循环是管理类游戏的核心。
_process() 中逐个处理 1000 个以上的实体;严格使用 Tick Manager 来批量更新或在轮换池中处理实体。Base * pow(1.15, Level))来维持挑战性和策略紧张感。duplicate() 以避免意外更新该类型的所有建筑。广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
_physics_process()RefCounted 或 Data Resources 以避免 SceneTree 的内存/CPU 开销。OS.low_processor_usage_mode;严格为静态管理界面启用它以节省大量 CPU/电池寿命。call_deferred() 进行线程安全的 UI 更新。.res 格式。is_equal_approx() 以防止逻辑门中的浮点数抖动故障。任何经营类游戏的核心都是其经济系统。关键原则:多种相互关联的资源,迫使玩家做出权衡。
class_name TycoonEconomy
extends Node
signal resource_changed(resource_type: String, amount: float)
signal went_bankrupt
var resources: Dictionary = {
"money": 10000.0,
"reputation": 50.0, # 0-100
"workers": 0,
"materials": 100.0,
"energy": 100.0
}
var resource_caps: Dictionary = {
"reputation": 100.0,
"workers": 50,
"energy": 1000.0
}
func modify_resource(type: String, amount: float) -> bool:
if amount < 0 and resources[type] + amount < 0:
if type == "money":
went_bankrupt.emit()
return false # 不能为负
resources[type] = clamp(
resources[type] + amount,
0,
resource_caps.get(type, INF)
)
resource_changed.emit(type, resources[type])
return true
class_name FinancialTracker
extends Node
var income_sources: Dictionary = {} # source_name: amount_per_tick
var expense_sources: Dictionary = {}
signal financial_update(profit: float, income: float, expenses: float)
func calculate_tick() -> float:
var total_income := 0.0
var total_expenses := 0.0
for source in income_sources.values():
total_income += source
for source in expense_sources.values():
total_expenses += source
var profit := total_income - total_expenses
financial_update.emit(profit, total_income, total_expenses)
return profit
模拟游戏需要可控的时间:
class_name SimulationTime
extends Node
signal time_tick(delta_game_hours: float)
signal day_changed(day: int)
signal speed_changed(new_speed: int)
enum Speed { PAUSED, NORMAL, FAST, ULTRA }
@export var seconds_per_game_hour := 30.0 # 真实秒数
var current_speed := Speed.NORMAL
var speed_multipliers := {
Speed.PAUSED: 0.0,
Speed.NORMAL: 1.0,
Speed.FAST: 3.0,
Speed.ULTRA: 10.0
}
var current_hour := 8.0 # 从上午 8 点开始
var current_day := 1
func _process(delta: float) -> void:
if current_speed == Speed.PAUSED:
return
var game_delta := (delta / seconds_per_game_hour) * speed_multipliers[current_speed]
current_hour += game_delta
if current_hour >= 24.0:
current_hour -= 24.0
current_day += 1
day_changed.emit(current_day)
time_tick.emit(game_delta)
func set_speed(speed: Speed) -> void:
current_speed = speed
speed_changed.emit(speed)
class_name Worker
extends Node
enum State { IDLE, WORKING, RESTING, COMMUTING }
@export var wage_per_hour: float = 10.0
@export var skill_level: float = 1.0 # 生产力乘数
@export var morale: float = 80.0 # 0-100
var current_state := State.IDLE
var assigned_workstation: Workstation
func update(game_hours: float) -> void:
match current_state:
State.WORKING:
if assigned_workstation:
var productivity := skill_level * (morale / 100.0)
assigned_workstation.work(game_hours * productivity)
morale -= game_hours * 0.5 # 工作使工人疲劳
State.RESTING:
morale = min(100.0, morale + game_hours * 2.0)
func calculate_hourly_cost() -> float:
return wage_per_hour
class_name Facility
extends Node3D
@export var build_cost: Dictionary # resource_type: amount
@export var operating_cost_per_hour: float = 5.0
@export var capacity: int = 5
@export var output_per_hour: Dictionary # resource_type: amount
var assigned_workers: Array[Worker] = []
var is_operational := true
var efficiency := 1.0
func calculate_output(game_hours: float) -> Dictionary:
if not is_operational or assigned_workers.is_empty():
return {}
var worker_efficiency := 0.0
for worker in assigned_workers:
worker_efficiency += worker.skill_level * (worker.morale / 100.0)
worker_efficiency /= capacity # 归一化到 0-1
var result := {}
for resource in output_per_hour:
result[resource] = output_per_hour[resource] * game_hours * worker_efficiency * efficiency
return result
class_name CustomerSimulation
extends Node
@export var base_customers_per_hour := 10.0
@export var demand_curve: Curve # 一天中的小时 vs 需求乘数
var customer_queue: Array[Customer] = []
func generate_customers(game_hour: float, delta_hours: float) -> void:
var demand_mult := demand_curve.sample(game_hour / 24.0)
var reputation_mult := Economy.resources["reputation"] / 50.0 # 100 声望 = 2 倍顾客
var customers_to_spawn := base_customers_per_hour * delta_hours * demand_mult * reputation_mult
for i in int(customers_to_spawn):
spawn_customer()
func spawn_customer() -> void:
var customer := Customer.new()
customer.patience = randf_range(30.0, 120.0) # 离开前的秒数
customer.spending_budget = randf_range(10.0, 100.0)
customer_queue.append(customer)
# 金钱飞向银行,资源流动等。
class_name ResourceFlowVisualizer
extends Node
func show_income(amount: float, from: Vector2, to: Vector2) -> void:
var coin := coin_scene.instantiate()
coin.position = from
add_child(coin)
var tween := create_tween()
tween.tween_property(coin, "position", to, 0.5)
tween.tween_callback(coin.queue_free)
var label := Label.new()
label.text = "+$" + str(int(amount))
label.position = from
add_child(label)
var label_tween := create_tween()
label_tween.tween_property(label, "position:y", label.position.y - 30, 0.5)
label_tween.parallel().tween_property(label, "modulate:a", 0.0, 0.5)
label_tween.tween_callback(label.queue_free)
class_name StatsDashboard
extends Control
@export var graph_history_hours := 24
var income_history: Array[float] = []
var expense_history: Array[float] = []
func record_financial_tick(income: float, expenses: float) -> void:
income_history.append(income)
expense_history.append(expenses)
# 保留最后 N 个条目
while income_history.size() > graph_history_hours:
income_history.pop_front()
expense_history.pop_front()
queue_redraw()
func _draw() -> void:
# 绘制收入/支出图表
draw_line_graph(income_history, Color.GREEN)
draw_line_graph(expense_history, Color.RED)
class_name UnlockSystem
extends Node
var unlocks: Dictionary = {
"basic_facility": true,
"advanced_facility": false,
"marketing": false,
"automation": false
}
var unlock_conditions: Dictionary = {
"advanced_facility": {"money_earned": 50000},
"marketing": {"reputation": 70},
"automation": {"workers_hired": 20}
}
var progress: Dictionary = {
"money_earned": 0.0,
"workers_hired": 0
}
func check_unlocks() -> Array[String]:
var newly_unlocked: Array[String] = []
for unlock in unlock_conditions:
if unlocks[unlock]:
continue # 已解锁
var conditions := unlock_conditions[unlock]
var all_met := true
for condition in conditions:
if progress.get(condition, 0) < conditions[condition]:
all_met = false
break
if all_met:
unlocks[unlock] = true
newly_unlocked.append(unlock)
return newly_unlocked
| 陷阱 | 解决方案 |
|---|---|
| 经济系统太容易被破坏 | 广泛的平衡、软上限、收益递减 |
| 游戏早期乏味 | 前置有趣的决策、快速的早期进度 |
| 信息过载 | 渐进式披露、可折叠的 UI 面板 |
| 没有明确目标 | 里程碑、成就、场景 |
| 繁琐的微观管理 | 自动化解锁、批量操作 |
Control 节点,Tree 用于列表,GraphEdit 用于连接Camera2D每周安装
69
仓库
GitHub 星标
64
首次出现
2026年2月10日
安全审计
安装于
codex63
gemini-cli63
opencode61
github-copilot60
kimi-cli59
cursor59
Optimization, systems mastery, and satisfying feedback loops define management games.
_process(); strictly use a Tick Manager to batch updates or process entities in rotating pools.Base * pow(1.15, Level)) to maintain challenge and strategic tension.duplicate() to avoid unintentionally updating every building of that type._physics_process() or delta accumulators for deterministic simulation results.RefCounted or Data Resources to avoid the memory/CPU overhead of the SceneTree.OS.low_processor_usage_mode ; strictly enable it for stationary management screens to save massive CPU/Battery life.call_deferred() for thread-safe UI updates..res formats.is_equal_approx() to prevent floating-point jitter failures in logic gates.The heart of any tycoon game is its economy. Key principle: multiple interconnected resources that force trade-offs.
class_name TycoonEconomy
extends Node
signal resource_changed(resource_type: String, amount: float)
signal went_bankrupt
var resources: Dictionary = {
"money": 10000.0,
"reputation": 50.0, # 0-100
"workers": 0,
"materials": 100.0,
"energy": 100.0
}
var resource_caps: Dictionary = {
"reputation": 100.0,
"workers": 50,
"energy": 1000.0
}
func modify_resource(type: String, amount: float) -> bool:
if amount < 0 and resources[type] + amount < 0:
if type == "money":
went_bankrupt.emit()
return false # Can't go negative
resources[type] = clamp(
resources[type] + amount,
0,
resource_caps.get(type, INF)
)
resource_changed.emit(type, resources[type])
return true
class_name FinancialTracker
extends Node
var income_sources: Dictionary = {} # source_name: amount_per_tick
var expense_sources: Dictionary = {}
signal financial_update(profit: float, income: float, expenses: float)
func calculate_tick() -> float:
var total_income := 0.0
var total_expenses := 0.0
for source in income_sources.values():
total_income += source
for source in expense_sources.values():
total_expenses += source
var profit := total_income - total_expenses
financial_update.emit(profit, total_income, total_expenses)
return profit
Simulation games need controllable time:
class_name SimulationTime
extends Node
signal time_tick(delta_game_hours: float)
signal day_changed(day: int)
signal speed_changed(new_speed: int)
enum Speed { PAUSED, NORMAL, FAST, ULTRA }
@export var seconds_per_game_hour := 30.0 # Real seconds
var current_speed := Speed.NORMAL
var speed_multipliers := {
Speed.PAUSED: 0.0,
Speed.NORMAL: 1.0,
Speed.FAST: 3.0,
Speed.ULTRA: 10.0
}
var current_hour := 8.0 # Start at 8 AM
var current_day := 1
func _process(delta: float) -> void:
if current_speed == Speed.PAUSED:
return
var game_delta := (delta / seconds_per_game_hour) * speed_multipliers[current_speed]
current_hour += game_delta
if current_hour >= 24.0:
current_hour -= 24.0
current_day += 1
day_changed.emit(current_day)
time_tick.emit(game_delta)
func set_speed(speed: Speed) -> void:
current_speed = speed
speed_changed.emit(speed)
class_name Worker
extends Node
enum State { IDLE, WORKING, RESTING, COMMUTING }
@export var wage_per_hour: float = 10.0
@export var skill_level: float = 1.0 # Productivity multiplier
@export var morale: float = 80.0 # 0-100
var current_state := State.IDLE
var assigned_workstation: Workstation
func update(game_hours: float) -> void:
match current_state:
State.WORKING:
if assigned_workstation:
var productivity := skill_level * (morale / 100.0)
assigned_workstation.work(game_hours * productivity)
morale -= game_hours * 0.5 # Working tires workers
State.RESTING:
morale = min(100.0, morale + game_hours * 2.0)
func calculate_hourly_cost() -> float:
return wage_per_hour
class_name Facility
extends Node3D
@export var build_cost: Dictionary # resource_type: amount
@export var operating_cost_per_hour: float = 5.0
@export var capacity: int = 5
@export var output_per_hour: Dictionary # resource_type: amount
var assigned_workers: Array[Worker] = []
var is_operational := true
var efficiency := 1.0
func calculate_output(game_hours: float) -> Dictionary:
if not is_operational or assigned_workers.is_empty():
return {}
var worker_efficiency := 0.0
for worker in assigned_workers:
worker_efficiency += worker.skill_level * (worker.morale / 100.0)
worker_efficiency /= capacity # Normalize to 0-1
var result := {}
for resource in output_per_hour:
result[resource] = output_per_hour[resource] * game_hours * worker_efficiency * efficiency
return result
class_name CustomerSimulation
extends Node
@export var base_customers_per_hour := 10.0
@export var demand_curve: Curve # Hour of day vs demand multiplier
var customer_queue: Array[Customer] = []
func generate_customers(game_hour: float, delta_hours: float) -> void:
var demand_mult := demand_curve.sample(game_hour / 24.0)
var reputation_mult := Economy.resources["reputation"] / 50.0 # 100 rep = 2x customers
var customers_to_spawn := base_customers_per_hour * delta_hours * demand_mult * reputation_mult
for i in int(customers_to_spawn):
spawn_customer()
func spawn_customer() -> void:
var customer := Customer.new()
customer.patience = randf_range(30.0, 120.0) # Seconds before leaving
customer.spending_budget = randf_range(10.0, 100.0)
customer_queue.append(customer)
# Money flying to bank, resources flowing, etc.
class_name ResourceFlowVisualizer
extends Node
func show_income(amount: float, from: Vector2, to: Vector2) -> void:
var coin := coin_scene.instantiate()
coin.position = from
add_child(coin)
var tween := create_tween()
tween.tween_property(coin, "position", to, 0.5)
tween.tween_callback(coin.queue_free)
var label := Label.new()
label.text = "+$" + str(int(amount))
label.position = from
add_child(label)
var label_tween := create_tween()
label_tween.tween_property(label, "position:y", label.position.y - 30, 0.5)
label_tween.parallel().tween_property(label, "modulate:a", 0.0, 0.5)
label_tween.tween_callback(label.queue_free)
class_name StatsDashboard
extends Control
@export var graph_history_hours := 24
var income_history: Array[float] = []
var expense_history: Array[float] = []
func record_financial_tick(income: float, expenses: float) -> void:
income_history.append(income)
expense_history.append(expenses)
# Keep last N entries
while income_history.size() > graph_history_hours:
income_history.pop_front()
expense_history.pop_front()
queue_redraw()
func _draw() -> void:
# Draw income/expense graph
draw_line_graph(income_history, Color.GREEN)
draw_line_graph(expense_history, Color.RED)
class_name UnlockSystem
extends Node
var unlocks: Dictionary = {
"basic_facility": true,
"advanced_facility": false,
"marketing": false,
"automation": false
}
var unlock_conditions: Dictionary = {
"advanced_facility": {"money_earned": 50000},
"marketing": {"reputation": 70},
"automation": {"workers_hired": 20}
}
var progress: Dictionary = {
"money_earned": 0.0,
"workers_hired": 0
}
func check_unlocks() -> Array[String]:
var newly_unlocked: Array[String] = []
for unlock in unlock_conditions:
if unlocks[unlock]:
continue # Already unlocked
var conditions := unlock_conditions[unlock]
var all_met := true
for condition in conditions:
if progress.get(condition, 0) < conditions[condition]:
all_met = false
break
if all_met:
unlocks[unlock] = true
newly_unlocked.append(unlock)
return newly_unlocked
| Pitfall | Solution |
|---|---|
| Economy too easy to break | Extensive balancing, soft caps, diminishing returns |
| Boring early game | Front-load interesting decisions, quick early progression |
| Information overload | Progressive disclosure, collapsible UI panels |
| No clear goals | Milestones, achievements, scenarios |
| Tedious micromanagement | Automation unlocks, batch operations |
Control nodes extensively, Tree for lists, GraphEdit for connectionsCamera2D with orthographic projectionWeekly Installs
69
Repository
GitHub Stars
64
First Seen
Feb 10, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
codex63
gemini-cli63
opencode61
github-copilot60
kimi-cli59
cursor59
GSAP 框架集成指南:Vue、Svelte 等框架中 GSAP 动画最佳实践
3,400 周安装