From 70c19e79722979214eaba4c4d44b5dba9b937a53 Mon Sep 17 00:00:00 2001 From: wjsjwr Date: Sat, 6 Dec 2025 18:54:23 +0800 Subject: [PATCH] MVP models --- ai/tasks/OkToPlayMobilePhone.cs | 34 ------- ai/tasks/OkToPlayMobilePhone.cs.uid | 1 - ai/watch_mobile_phone.tres | 79 ---------------- scenes/student.tscn | 12 --- scripts/GameManager.cs | 141 +++++++++++++++++++++++++++- scripts/Models/MentorModel.cs | 40 ++++++++ scripts/Models/MentorModel.cs.uid | 1 + scripts/Models/PropertyValue.cs | 122 ++++++++++++++++++++++++ scripts/Models/PropertyValue.cs.uid | 1 + scripts/Models/StatusValue.cs | 101 ++++++++++++++++++++ scripts/Models/StatusValue.cs.uid | 1 + scripts/Models/StudentModel.cs | 63 +++++++++++++ scripts/Models/StudentModel.cs.uid | 1 + scripts/Models/Task.cs | 97 +++++++++++++++++++ scripts/Models/Task.cs.uid | 1 + scripts/Models/UnitModel.cs | 78 +++++++++++++++ scripts/Models/UnitModel.cs.uid | 1 + scripts/Student.cs | 21 ++++- 最强导师.csproj | 1 + 19 files changed, 668 insertions(+), 128 deletions(-) delete mode 100644 ai/tasks/OkToPlayMobilePhone.cs delete mode 100644 ai/tasks/OkToPlayMobilePhone.cs.uid delete mode 100644 ai/watch_mobile_phone.tres create mode 100644 scripts/Models/MentorModel.cs create mode 100644 scripts/Models/MentorModel.cs.uid create mode 100644 scripts/Models/PropertyValue.cs create mode 100644 scripts/Models/PropertyValue.cs.uid create mode 100644 scripts/Models/StatusValue.cs create mode 100644 scripts/Models/StatusValue.cs.uid create mode 100644 scripts/Models/StudentModel.cs create mode 100644 scripts/Models/StudentModel.cs.uid create mode 100644 scripts/Models/Task.cs create mode 100644 scripts/Models/Task.cs.uid create mode 100644 scripts/Models/UnitModel.cs create mode 100644 scripts/Models/UnitModel.cs.uid diff --git a/ai/tasks/OkToPlayMobilePhone.cs b/ai/tasks/OkToPlayMobilePhone.cs deleted file mode 100644 index c1dc6ff..0000000 --- a/ai/tasks/OkToPlayMobilePhone.cs +++ /dev/null @@ -1,34 +0,0 @@ -using Godot; -using System; - -[Tool] -public partial class OkToPlayMobilePhone : BTCondition -{ - [Export] - public StringName target; - - public override Status _Tick(double delta) - { - Student student = Agent as Student; // Cast the agent to a Student object - if (student == null) return Status.Failure; - - if (student.State == Student.CharacterState.Idle) { - return Status.Success; - } - - if (student.State == Student.CharacterState.Sitting && student.TargetDirection == Student.Direction.Down) { - return Status.Success; - } - - return Status.Failure; - } - public override string[] _GetConfigurationWarnings() - { - return Array.Empty(); - } - - public override string _GenerateName() - { - return "OkToPlayMobilePhone"; - } -} diff --git a/ai/tasks/OkToPlayMobilePhone.cs.uid b/ai/tasks/OkToPlayMobilePhone.cs.uid deleted file mode 100644 index 3b1ae74..0000000 --- a/ai/tasks/OkToPlayMobilePhone.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://b3ukdvcoxly13 diff --git a/ai/watch_mobile_phone.tres b/ai/watch_mobile_phone.tres deleted file mode 100644 index 861674c..0000000 --- a/ai/watch_mobile_phone.tres +++ /dev/null @@ -1,79 +0,0 @@ -[gd_resource type="BehaviorTree" load_steps=14 format=3 uid="uid://cdsixeqsdfmc1"] - -[ext_resource type="Script" uid="uid://b3ukdvcoxly13" path="res://ai/tasks/OkToPlayMobilePhone.cs" id="1_lfwnu"] - -[sub_resource type="BlackboardPlan" id="BlackboardPlan_gwwr7"] -resource_local_to_scene = false -resource_name = "" - -[sub_resource type="BTCondition" id="BTCondition_prnjq"] -resource_local_to_scene = false -resource_name = "" -target = &"" -script = ExtResource("1_lfwnu") -target = &"" - -[sub_resource type="BBNode" id="BBNode_7pcle"] -resource_local_to_scene = false -resource_name = "AnimationPlayer" -saved_value = NodePath("AnimationPlayer") - -[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_hx8gl"] -resource_local_to_scene = false -resource_name = "" -await_completion = 1.2 -animation_player = SubResource("BBNode_7pcle") -animation_name = &"phone_up" - -[sub_resource type="BBNode" id="BBNode_6275u"] -resource_local_to_scene = false -resource_name = "AnimationPlayer" -saved_value = NodePath("AnimationPlayer") - -[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_wbk5l"] -resource_local_to_scene = false -resource_name = "" -await_completion = 1.0 -animation_player = SubResource("BBNode_6275u") -animation_name = &"phone_loop" - -[sub_resource type="BTRepeat" id="BTRepeat_1nqee"] -resource_local_to_scene = false -resource_name = "" -children = [SubResource("BTPlayAnimation_wbk5l")] -times = 3 - -[sub_resource type="BTProbability" id="BTProbability_x3mt2"] -resource_local_to_scene = false -resource_name = "" -children = [SubResource("BTRepeat_1nqee")] -run_chance = 0.75 - -[sub_resource type="BTRepeatUntilFailure" id="BTRepeatUntilFailure_uatr3"] -resource_local_to_scene = false -resource_name = "" -children = [SubResource("BTProbability_x3mt2")] - -[sub_resource type="BBNode" id="BBNode_2433i"] -resource_local_to_scene = false -resource_name = "AnimationPlayer" -saved_value = NodePath("AnimationPlayer") - -[sub_resource type="BTPlayAnimation" id="BTPlayAnimation_g4biw"] -resource_local_to_scene = false -resource_name = "" -await_completion = 0.5 -animation_player = SubResource("BBNode_2433i") -animation_name = &"phone_down" - -[sub_resource type="BTSequence" id="BTSequence_0drub"] -resource_local_to_scene = false -resource_name = "" -children = [SubResource("BTCondition_prnjq"), SubResource("BTPlayAnimation_hx8gl"), SubResource("BTRepeatUntilFailure_uatr3"), SubResource("BTPlayAnimation_g4biw")] - -[resource] -resource_local_to_scene = false -resource_name = "" -description = "WatchMobilePhone" -blackboard_plan = SubResource("BlackboardPlan_gwwr7") -root_task = SubResource("BTSequence_0drub") diff --git a/scenes/student.tscn b/scenes/student.tscn index 12c11a2..5a6d70d 100644 --- a/scenes/student.tscn +++ b/scenes/student.tscn @@ -933,15 +933,3 @@ libraries = { [node name="StudentName" type="Node" parent="."] script = ExtResource("8_kvqca") - -[node name="BTPlayer" type="BTPlayer" parent="."] -_import_path = NodePath("") -unique_name_in_owner = false -process_mode = 0 -process_priority = 0 -process_physics_priority = 0 -process_thread_group = 0 -physics_interpolation_mode = 0 -auto_translate_mode = 0 -editor_description = "" -script = null diff --git a/scripts/GameManager.cs b/scripts/GameManager.cs index 8a330cb..2583fcf 100644 --- a/scripts/GameManager.cs +++ b/scripts/GameManager.cs @@ -1,5 +1,7 @@ using Godot; using System; +using System.Collections.Generic; +using Models; public partial class GameManager : Node { @@ -9,17 +11,154 @@ public partial class GameManager : Node 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"); - // Called when the node enters the scene tree for the first time. + + // --- Core Loop Definitions --- + public enum GamePhase + { + Planning, // 筹备阶段:时间暂停,分配任务,购买设施 + Execution, // 执行阶段:时间流动,学生工作 + Review, // 结算阶段:回合结束,发工资,结算成果 + } + + [Export] + public int MaxTurns = 30; + + // --- Global State --- + public static GamePhase CurrentPhase { get; private set; } = GamePhase.Planning; + public static int CurrentTurn { get; private set; } = 1; + + // --- Domain Model --- + public MentorModel Mentor { get; private set; } = new MentorModel(); + public List Students { get; private set; } = new List(); + public List ActiveTasks { get; private set; } = new List(); + + // --- 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() + { + CurrentTurn = 1; + CurrentPhase = GamePhase.Planning; + + // MVP: Add a test student + var s1 = new StudentModel("张三"); + Students.Add(s1); + + // MVP: Add a test task + var t1 = new Task("深度学习导论", TaskType.Paper, 1000f, 3); + 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 + } } + /// + /// 结束筹备阶段,开始执行 + /// + public void StartExecution() + { + if (CurrentPhase != GamePhase.Planning) return; + + CurrentPhase = GamePhase.Execution; + 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) + } + /// + /// 结束执行阶段(通常由时间耗尽或玩家手动触发),进入结算 + /// + public void EndExecution() + { + if (CurrentPhase != GamePhase.Execution) return; + CurrentPhase = GamePhase.Review; + EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase); + GD.Print("Phase Changed: Review"); + + PerformReview(); + } + + /// + /// 执行结算逻辑,并准备下一回合 + /// + private void PerformReview() + { + // 1. Task progress check + foreach (var task in ActiveTasks) + { + task.Deadline--; + if (task.IsCompleted) + { + GD.Print($"Task {task.Name} Completed!"); + Mentor.Reputation += task.RewardReputation; + Mentor.Money += task.RewardMoney; + } + else if (task.IsFailed) + { + GD.Print($"Task {task.Name} Failed!"); + Mentor.Reputation -= 10; // Penalty + } + } + + // 2. Student status update (Salary, etc.) + foreach (var student in Students) + { + // Deduct salary? Restore some stamina? + } + + GD.Print("Review Complete. Waiting for Next Turn confirmation."); + } + + /// + /// 开始新的回合 + /// + public void StartNextTurn() + { + if (CurrentPhase != GamePhase.Review) return; + + CurrentTurn++; + if (CurrentTurn > MaxTurns) + { + GD.Print("Game Over!"); + // Handle Game Over + return; + } + + CurrentPhase = GamePhase.Planning; + EmitSignal(SignalName.TurnChanged, CurrentTurn); + EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase); + + // Refresh resources/AP + Mentor.Energy.Current = Mentor.Energy.UpperThreshold; + + GD.Print($"Turn {CurrentTurn} Started. Phase: Planning"); + } } diff --git a/scripts/Models/MentorModel.cs b/scripts/Models/MentorModel.cs new file mode 100644 index 0000000..f562de9 --- /dev/null +++ b/scripts/Models/MentorModel.cs @@ -0,0 +1,40 @@ +namespace Models; + +/// +/// 导师数据模型 (MentorModel) +/// 玩家的数值状态。 +/// +public class MentorModel +{ + public enum MentorModeType + { + Worker, + Manager + } + /// + /// 精力值 (Energy) + /// 用于释放技能(画饼、PUA、甚至亲自写代码)。 + /// 每回合恢复。 + /// + public StatusValue Energy { get; set; } + + /// + /// 经费 (Money/Funds) + /// 单位:元。用于发工资、买设备。 + /// + public int Money { get; set; } = 50000; + + /// + /// 学术声望 (Reputation) + /// 影响招生质量、项目申请成功率。 + /// + public int Reputation { get; set; } = 0; + + /// + /// 算力/数据资源 (ResearchPoints) + /// 用于攻克高难度 AI 课题。 + /// + public int ResearchPoints { get; set; } = 0; + + public MentorModeType Mode { get; set; } = MentorModeType.Worker; +} \ No newline at end of file diff --git a/scripts/Models/MentorModel.cs.uid b/scripts/Models/MentorModel.cs.uid new file mode 100644 index 0000000..6467329 --- /dev/null +++ b/scripts/Models/MentorModel.cs.uid @@ -0,0 +1 @@ +uid://dyehdtnucytg2 diff --git a/scripts/Models/PropertyValue.cs b/scripts/Models/PropertyValue.cs new file mode 100644 index 0000000..55b9584 --- /dev/null +++ b/scripts/Models/PropertyValue.cs @@ -0,0 +1,122 @@ +using System; + +namespace Models; + +/// +/// 属性值类型 +/// 封装了整型数值,提供最大值限制(100)和显示转换。 +/// +public class PropertyValue +{ + public const int Min = 0; + public const int Max = 100; + + private float _value; + + /// + /// 获取或设置当前值。 + /// 设置时会自动限制在 [Min, Max] 范围内。 + /// + public float Value + { + get => _value; + set + { + _value = value; + if (_value > Max) _value = Max; + if (_value < Min) _value = Min; + } + } + + public PropertyValue(int value) + { + Value = value; + } + + public PropertyValue(float value) + { + Value = value; + } + + public PropertyValue() : this(0) { } + + /// + /// 获取显示值 (Value / 100.0f) + /// + public int Display() => (int)_value; + + public override string ToString() + { + return Display().ToString(); + } + + // --- 隐式转换 (实现“重载等号”效果) --- + + // 允许 int 直接赋值给 PropertyValue (创建新实例) + public static implicit operator PropertyValue(int value) + { + return new PropertyValue(value); + } + + // 允许 int 直接赋值给 PropertyValue (创建新实例) + public static implicit operator PropertyValue(float value) + { + return new PropertyValue(value); + } + + // 允许 PropertyValue 像 int 一样使用 + public static implicit operator int(PropertyValue p) + { + return (int)p._value; + } + + // 允许 PropertyValue 像 float 一样使用 + public static implicit operator float(PropertyValue p) + { + return p._value; + } + + // --- 运算符重载 (支持 int 计算) --- + + public static PropertyValue operator +(PropertyValue a, int b) => new(a._value + b); + public static PropertyValue operator +(int a, PropertyValue b) => new(a + b._value); + + public static PropertyValue operator -(PropertyValue a, int b) => new(a._value - b); + public static PropertyValue operator -(int a, PropertyValue b) => new(a - b._value); + + public static PropertyValue operator *(PropertyValue a, int b) => new(a._value * b); + public static PropertyValue operator *(int a, PropertyValue b) => new(a * b._value); + + public static PropertyValue operator /(PropertyValue a, int b) + { + return b == 0 ? throw new DivideByZeroException() : new PropertyValue(a._value / b); + } + public static PropertyValue operator /(int a, PropertyValue b) + { + return b._value == 0 ? throw new DivideByZeroException() : new PropertyValue(a / b._value); + } + + // --- 运算符重载 (支持 float 计算) --- + + public static PropertyValue operator +(PropertyValue a, float b) => new(a._value + b); + public static PropertyValue operator +(float a, PropertyValue b) => new(a + b._value); + + public static PropertyValue operator -(PropertyValue a, float b) => new(a._value - b); + public static PropertyValue operator -(float a, PropertyValue b) => new(a - b._value); + + public static PropertyValue operator *(PropertyValue a, float b) => new(a._value * b); + public static PropertyValue operator *(float a, PropertyValue b) => new(a * b._value); + + public static PropertyValue operator /(PropertyValue a, float b) => new(a._value / b); + public static PropertyValue operator /(float a, PropertyValue b) => new(a / b._value); + + // --- 运算符重载 (PropertyValue 之间) --- + + public static PropertyValue operator +(PropertyValue a, PropertyValue b) => new(a._value + b._value); + public static PropertyValue operator -(PropertyValue a, PropertyValue b) => new(a._value - b._value); + public static PropertyValue operator *(PropertyValue a, PropertyValue b) => new(a._value * b._value); + public static PropertyValue operator /(PropertyValue a, PropertyValue b) + { + return b._value == 0 ? throw new DivideByZeroException() : new PropertyValue(a._value / b._value); + } +} \ No newline at end of file diff --git a/scripts/Models/PropertyValue.cs.uid b/scripts/Models/PropertyValue.cs.uid new file mode 100644 index 0000000..46d1d01 --- /dev/null +++ b/scripts/Models/PropertyValue.cs.uid @@ -0,0 +1 @@ +uid://l58i2kmspq7c diff --git a/scripts/Models/StatusValue.cs b/scripts/Models/StatusValue.cs new file mode 100644 index 0000000..4722ad7 --- /dev/null +++ b/scripts/Models/StatusValue.cs @@ -0,0 +1,101 @@ +using System; + +namespace Models; + +/// +/// 状态值 (StatusValue) +/// 维护当前状态值以及上限和下限阈值。 +/// +public class StatusValue +{ + private PropertyValue _current; + private PropertyValue _upperThreshold; + private PropertyValue _lowerThreshold; + + /// + /// 当 Current >= UpperThreshold 时触发此事件 + /// + public event Action OnUpperThresholdReached; + + /// + /// 当 Current <= LowerThreshold 时触发此事件 + /// + public event Action OnLowerThresholdReached; + + /// + /// 当前状态值 + /// 修改时会自动检测阈值。 + /// + public PropertyValue Current + { + get => _current; + set + { + _current = value; + CheckThresholds(); + } + } + + /// + /// 上限阈值 + /// + public PropertyValue UpperThreshold + { + get => _upperThreshold; + set + { + _upperThreshold = value; + CheckThresholds(); + } + } + + /// + /// 下限阈值 + /// + public PropertyValue LowerThreshold + { + get => _lowerThreshold; + set + { + _lowerThreshold = value; + CheckThresholds(); + } + } + + public StatusValue(int current = 0, int upper = 100, int lower = 0) + { + _current = new PropertyValue(current); + _upperThreshold = new PropertyValue(upper); + _lowerThreshold = new PropertyValue(lower); + } + + public StatusValue(PropertyValue current, PropertyValue upper, PropertyValue lower) + { + _current = current ?? new PropertyValue(0); + _upperThreshold = upper ?? new PropertyValue(100); + _lowerThreshold = lower ?? new PropertyValue(0); + } + + private void CheckThresholds() + { + if ((int)_current >= (int)_upperThreshold) + { + OnUpperThresholdReached?.Invoke(); + } + + if ((int)_current <= (int)_lowerThreshold) + { + OnLowerThresholdReached?.Invoke(); + } + } + + public void Add(int value) + { + Current += value; // 触发 setter -> CheckThresholds + } + + public void Subtract(int value) + { + Current -= value; // 触发 setter -> CheckThresholds + } +} \ No newline at end of file diff --git a/scripts/Models/StatusValue.cs.uid b/scripts/Models/StatusValue.cs.uid new file mode 100644 index 0000000..314376b --- /dev/null +++ b/scripts/Models/StatusValue.cs.uid @@ -0,0 +1 @@ +uid://no453n0ubri1 diff --git a/scripts/Models/StudentModel.cs b/scripts/Models/StudentModel.cs new file mode 100644 index 0000000..d475a6e --- /dev/null +++ b/scripts/Models/StudentModel.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; + +namespace Models; + +/// +/// 学生数据模型 (StudentModel) +/// 包含学生的数值、状态和特质。 +/// 与 Godot 的 Node (View) 分离,便于序列化和逻辑处理。 +/// +public class StudentModel: UnitModel +{ + public enum StudentType + { + MasterCandidate, + DoctorCandidate + } + + // --- 静态属性 (Property) --- + /// + /// 学生类型 + /// + public StudentType Type { get; private set; } + + // --- 动态状态 (Status) --- + + /// + /// 体力 (Stamina) + /// 范围 0-100。工作消耗体力,休息恢复。体力过低效率下降。 + /// + public StatusValue Stamina { get; set; } + + /// + /// 忠诚度 (Loyalty) + /// 范围 0-100。过低可能跳槽或举报。 + /// + public StatusValue Loyalty { get; set; } + + /// + /// 年级 + /// + public StatusValue Grade { get; set; } + + /// + /// 记录对每个 Task 的贡献量,用于署名分配 + /// + public Dictionary Contributions { get; set; } + + /// + /// 特质列表 (如 "DDL战士", "卷王") + /// + public List Traits { get; set; } = []; + + public StudentModel(string name) : base(name) + { + var random = new Random(); + Stamina = new StatusValue(random.Next(100),100, 0); + Loyalty = new StatusValue(80, 100, 0); + Type = random.Next(2) == 0 ? StudentType.MasterCandidate : StudentType.DoctorCandidate; + Grade = new StatusValue(0, Type == StudentType.DoctorCandidate ? 6 : 3); + } +} + diff --git a/scripts/Models/StudentModel.cs.uid b/scripts/Models/StudentModel.cs.uid new file mode 100644 index 0000000..64484d3 --- /dev/null +++ b/scripts/Models/StudentModel.cs.uid @@ -0,0 +1 @@ +uid://eoh7yvyhct5d diff --git a/scripts/Models/Task.cs b/scripts/Models/Task.cs new file mode 100644 index 0000000..c11e96b --- /dev/null +++ b/scripts/Models/Task.cs @@ -0,0 +1,97 @@ +using System; +using System.Collections.Generic; + +namespace Models; + +/// +/// 任务类型枚举 +/// +public enum TaskType +{ + Paper, // 论文:重学术(Intelligence) + 表达(Expression) + Project, // 项目:重工程(Strength) + 学术(Intelligence) + Admin // 杂务:消耗体力,低收益,但必须做 +} + +/// +/// 任务 (Task) +/// 核心游戏对象之一,相当于地图上的“怪物”。 +/// 学生需要“攻击”任务(消耗工作量)来完成它。 +/// +public class Task +{ + public Guid Id { get; private set; } = Guid.NewGuid(); + + /// + /// 任务名称 + /// + public string Name { get; set; } + + /// + /// 任务类型 + /// + public TaskType Type { get; set; } + + /// + /// 总工作量 (HP) + /// + public float TotalWorkload { get; set; } + + /// + /// 当前进度 + /// + public float CurrentProgress { get; set; } + + /// + /// 难度系数 (Defense) + /// 影响学生攻克该任务的效率。若学生能力低于难度,效率会大幅下降。 + /// + public float Difficulty { get; set; } + + /// + /// 截止日期 (剩余回合数) + /// 归零时如果未完成,触发失败惩罚。 + /// + public int Deadline { get; set; } + + /// + /// 奖励:经费 + /// + public int RewardMoney { get; set; } + + /// + /// 奖励:声望 + /// + public int RewardReputation { get; set; } + + /// + /// 任务是否已完成 + /// + public bool IsCompleted => CurrentProgress >= TotalWorkload; + + /// + /// 任务是否已失败(超时未完成) + /// + public bool IsFailed => Deadline <= 0 && !IsCompleted; + + public Task(string name, TaskType type, float workload, int deadline) + { + Name = name; + Type = type; + TotalWorkload = workload; + Deadline = deadline; + CurrentProgress = 0; + Difficulty = 1.0f; + } + + /// + /// 增加进度 + /// + /// 工作量数值 + public void AddProgress(float amount) + { + CurrentProgress += amount; + if (CurrentProgress > TotalWorkload) CurrentProgress = TotalWorkload; + } +} + diff --git a/scripts/Models/Task.cs.uid b/scripts/Models/Task.cs.uid new file mode 100644 index 0000000..39f845d --- /dev/null +++ b/scripts/Models/Task.cs.uid @@ -0,0 +1 @@ +uid://052kca2012sn diff --git a/scripts/Models/UnitModel.cs b/scripts/Models/UnitModel.cs new file mode 100644 index 0000000..4e7c711 --- /dev/null +++ b/scripts/Models/UnitModel.cs @@ -0,0 +1,78 @@ +using Godot; +using System; + +namespace Models; + +/// +/// 所有角色的基类,无论是导师、学生还是博后。 +/// +public class UnitModel +{ + public Guid Id { get; private set; } = Guid.NewGuid(); + public string Name { get; set; } + + // 基础属性 + + /// + /// 学术能力,影响科研进度 + /// + public PropertyValue Academic {get; set;} + /// + /// 工程能力,影响实验进度 + /// + public PropertyValue Engineering {get; set;} + /// + /// 写作能力,影响论文发表 + /// + public PropertyValue Writing {get; set;} + /// + /// 财务能力,影响资金相关任务 + /// + public PropertyValue Financial {get; set;} + /// + /// 社交能力 + /// + public PropertyValue Social {get; set;} + /// + /// 行动力,影响各种行为的效率和能动性 + /// + public PropertyValue Activation {get; set;} + + // 状态属性 + + /// + /// 压力值 + /// + public StatusValue Stress {get; set;} + /// + /// 精神值 (Sanity) / 抗压能力 + /// 范围 0-100。过低会导致崩溃(Breakdown)。 + /// + public StatusValue Sanity { get; set; } + /// + /// 情绪值,影响工作效率 + /// + public PropertyValue Mood {get; set;} + /// + /// 移动速度 + /// + public float MoveSpeed {get; set;} + + // 局内属性 + + public Vector2I TargetPosition {get; set;} + public Vector2I CurrentPosition {get; set;} + public Guid TargetTaskId {get; set;} + + protected UnitModel(string name) + { + Name = name; + var random = new Random(); + Academic = random.Next(PropertyValue.Min, PropertyValue.Max); + Engineering = random.Next(PropertyValue.Min, PropertyValue.Max); + Writing = random.Next(PropertyValue.Min, PropertyValue.Max); + Financial = random.Next(PropertyValue.Min, PropertyValue.Max); + Social = random.Next(PropertyValue.Min, PropertyValue.Max); + Activation = random.Next(PropertyValue.Min, PropertyValue.Max); + } +} \ No newline at end of file diff --git a/scripts/Models/UnitModel.cs.uid b/scripts/Models/UnitModel.cs.uid new file mode 100644 index 0000000..8ea7de8 --- /dev/null +++ b/scripts/Models/UnitModel.cs.uid @@ -0,0 +1 @@ +uid://hremnrofal6l diff --git a/scripts/Student.cs b/scripts/Student.cs index 94a66ad..2545776 100644 --- a/scripts/Student.cs +++ b/scripts/Student.cs @@ -2,6 +2,7 @@ using Godot; using System; using System.Collections.Generic; using System.Linq; +using Models; // ReSharper disable CheckNamespace public partial class Student : CharacterBody2D @@ -9,6 +10,16 @@ public partial class Student : CharacterBody2D public float Speed { get; set; } = 8.0f; public const float JumpVelocity = -400.0f; + // --- MVP: Model Binding --- + public StudentModel Model { get; private set; } + + public void BindData(StudentModel model) + { + Model = model; + GD.Print($"Student bound to model: {Model.Name}"); + } + // -------------------------- + public int NextType = -1; private Queue PathToGo = new(); @@ -140,7 +151,15 @@ public partial class Student : CharacterBody2D animationPlayer = GetNode("AnimationPlayer"); animationPlayer.Play("idle_front"); var name_test = GetNode("StudentName"); - GD.Print("生成的名字是: " + name_test.GenerateName()); + + // MVP: Initialize Model if null + if (Model == null) + { + Model = new StudentModel(name_test.GenerateName()); + GD.Print($"[Auto-Init] Student: {Model.Name}"); + } else { + GD.Print("生成的名字是: " + name_test.GenerateName()); // Keep original log for reference + } } public void MoveFollowPath(List path) diff --git a/最强导师.csproj b/最强导师.csproj index 2f1fb77..7927da9 100644 --- a/最强导师.csproj +++ b/最强导师.csproj @@ -6,6 +6,7 @@ +