godot-genre-simulation

安装量: 56
排名: #13155

安装

npx skills add https://github.com/thedivergentai/gd-agentic-skills --skill godot-genre-simulation

Genre: Simulation / Tycoon Optimization, systems mastery, and satisfying feedback loops define management games. Available Scripts sim_tick_manager.gd Expert tick-based simulation with variable speed control and batch processing. Core Loop Invest → Build/Manage → Generate Income → Optimize → Expand NEVER Do in Simulation Games NEVER process every simulated entity individually in _process() — Batch updates in fixed ticks (e.g., once per second). Simulating 1000 businesses individually = 60k calls/second. Batch = 1k calls/second. NEVER use floating-point for currency — float accumulates rounding errors. $1.10 * 3 = $3.2999999. Use int cents: 1100 * 3 = 3300 cents = $33.00 exact. NEVER let early game be dull waiting — Front-load decision points. First 5 minutes must hook players. Don't make them wait 10 real minutes for first unlock. NEVER use linear cost scaling — Buildings that cost 10 * level break at level 100 (1000 cost). Use exponential: BASE * pow(1.5, level) creates meaningful trade-offs. NEVER hide critical numbers from players — Show income/expense breakdown, production rates, efficiency %. Optimization games require transparency. NEVER allow infinite resource stacking without consequence — Storage caps create interesting decisions. Unlimited resources remove strategy. NEVER update UI labels every frame — Updating 50 UI labels @60fps = 3000 updates/sec. Use signals: update only when value changes. Economy Design The heart of any tycoon game is its economy. Key principle: multiple interconnected resources that force trade-offs . Multi-Resource System 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 Income/Expense Tracking 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 Time System 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 ) Entity Management Workers/NPCs 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 Buildings/Facilities 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 Customer/Demand System 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 ) Feedback Systems Visual Feedback

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 ) Statistics Dashboard 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 ) Progression & Unlocks 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
Common Pitfalls
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
Godot-Specific Tips
UI
Use
Control
nodes extensively,
Tree
for lists,
GraphEdit
for connections
Performance
Process entities in batches, not every frame
Save/Load
Convert all game state to Dictionary for JSON serialization
Isometric view
Use Camera2D with orthographic projection Reference Master Skill: godot-master
返回排行榜