supervisor-simulator/scripts/GameManager.cs
wjsjwr 9c1593e717 已把 TaskSystem/SynergySystem/EconomySystem 按设计文档的“核心规则”落地成可运行逻辑,并把回合结算从 GameManager 下沉到系统与事件流上。
- 任务推进与结算:执行阶段按任务类型用属性权重计算进度、考虑角色/学科匹配、状态衰减与难度缩放,回合结束统一扣 Deadline、判定完成/失败并派发事件,同时记录署名贡献度 scripts/Core/GameSystems.cs
  - 经济结算:接收任务事件发奖惩,学术探索根据难度生成论文卡;回合结束统一扣工资并结息(经济学学科触发基础利率)scripts/Core/GameSystems.cs
  - 羁绊层数与效果:统计人群画像/职能分工堆叠,激活层级并聚合为全局 ModifierBundle 给数值解析器使用 scripts/Core/GameSystems.cs, scripts/Models/GameState.cs
  - 事件与数值解析支撑:新增领域事件与统一属性合成器,兼容羁绊/学科/特质/装备的叠加 scripts/Core/DomainEvents.cs, scripts/Core/StatResolver.cs
  - 回合结算入口调整:Review 阶段改由系统处理并发布回合结束事件 scripts/GameManager.cs
2026-01-01 00:07:16 +08:00

161 lines
4.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Godot;
using System;
using System.Collections.Generic;
using Models;
using Core;
/// <summary>
/// 游戏主控制节点MVC 的桥接层)
/// 设计说明:
/// 1) 负责初始化 GameSession并把输入/信号转交给 Controller/System。
/// 2) 仅做“流程调度”,不直接计算复杂数值,避免逻辑堆积。
/// 注意事项:
/// - View 与 Model 的绑定应逐步迁移到独立 View 脚本,避免在此类膨胀。
/// 未来扩展:
/// - 可拆分为 SceneRoot + UIController + DebugController分层管理。
/// </summary>
public partial class GameManager : Node
{
/// <summary>
/// Indicates if the game is currently in tutorial mode.
/// </summary>
public static bool IsTutorial { get; private set; }
public static string NextScene { get; set; } = null;
public static readonly Resource Arrow2X = ResourceLoader.Load("res://temp_res/kenney_ui-pack-space-expansion/PNG/Extra/Double/cursor_f.png");
[Export]
public int MaxTurns = 30;
// --- Global State ---
public GameSession Session { get; private set; }
public GameState State => Session?.State;
public GameController Controller { get; private set; }
public GamePhase CurrentPhase => State?.Turn.Phase ?? GamePhase.Planning;
public int CurrentTurn => State?.Turn.CurrentTurn ?? 1;
// --- Domain Model ---
public MentorModel Mentor => State?.Roster.Mentor;
public List<StudentModel> Students => State?.Roster.Students;
public List<TaskModel> ActiveTasks => State?.Tasks.ActiveTasks;
public EconomyState Economy => State?.Economy;
// --- Signals ---
[Signal] public delegate void PhaseChangedEventHandler(int phase); // int cast of GamePhase
[Signal] public delegate void TurnChangedEventHandler(int turn);
// Singleton instance access (if needed, though Godot uses node paths)
public static GameManager Instance { get; private set; }
public override void _EnterTree()
{
Instance = this;
}
public override void _Ready()
{
Input.SetCustomMouseCursor(Arrow2X);
// MVP Initialization
InitializeGame();
}
private void InitializeGame()
{
Session = GameSession.CreateDefault();
Controller = new GameController();
Controller.Initialize(Session);
State.Turn.MaxTurns = MaxTurns;
State.Turn.CurrentTurn = 1;
State.Turn.Phase = GamePhase.Planning;
// MVP: Add a test student
var s1 = new StudentModel("张三");
Students.Add(s1);
// MVP: Add a test task
var t1 = new TaskModel("深度学习导论", TaskKind.AcademicExploration, 1000f, 3);
t1.Reward.Money = 1000;
t1.Reward.Reputation = 5;
ActiveTasks.Add(t1);
GD.Print("Game Initialized. Phase: Planning, Turn: 1");
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
if (CurrentPhase == GamePhase.Execution)
{
// Update game logic (timers, etc.)
// In a real implementation, this might manage the global timer for the day/week
}
Session?.Tick((float)delta);
}
/// <summary>
/// 结束筹备阶段,开始执行
/// </summary>
public void StartExecution()
{
if (CurrentPhase != GamePhase.Planning) return;
Controller.StartExecution();
EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase);
GD.Print("Phase Changed: Execution");
// Notify all agents to start working (this would be handled by a system listening to the signal)
}
/// <summary>
/// 结束执行阶段(通常由时间耗尽或玩家手动触发),进入结算
/// </summary>
public void EndExecution()
{
if (CurrentPhase != GamePhase.Execution) return;
Controller.EndExecution();
EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase);
GD.Print("Phase Changed: Review");
PerformReview();
}
/// <summary>
/// 执行结算逻辑,并准备下一回合
/// </summary>
private void PerformReview()
{
Session.Systems.Task.ResolveEndOfTurn();
Session.Events.Publish(new TurnEndedEvent(CurrentTurn));
GD.Print("Review Complete. Waiting for Next Turn confirmation.");
}
/// <summary>
/// 开始新的回合
/// </summary>
public void StartNextTurn()
{
if (CurrentPhase != GamePhase.Review) return;
Controller.StartNextTurn();
if (CurrentTurn > State.Turn.MaxTurns)
{
GD.Print("Game Over!");
// Handle Game Over
return;
}
State.Turn.Phase = GamePhase.Planning;
EmitSignal(SignalName.TurnChanged, CurrentTurn);
EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase);
// Refresh resources/AP
Mentor.Resources.Energy.Current.Value = Mentor.Resources.Energy.UpperThreshold;
GD.Print($"Turn {CurrentTurn} Started. Phase: Planning");
}
}