MVP models
This commit is contained in:
parent
8e81f2a12b
commit
70c19e7972
@ -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<string>();
|
||||
}
|
||||
|
||||
public override string _GenerateName()
|
||||
{
|
||||
return "OkToPlayMobilePhone";
|
||||
}
|
||||
}
|
||||
@ -1 +0,0 @@
|
||||
uid://b3ukdvcoxly13
|
||||
@ -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")
|
||||
@ -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
|
||||
|
||||
@ -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<StudentModel> Students { get; private set; } = new List<StudentModel>();
|
||||
public List<Task> ActiveTasks { get; private set; } = new List<Task>();
|
||||
|
||||
// --- 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
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束筹备阶段,开始执行
|
||||
/// </summary>
|
||||
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)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 结束执行阶段(通常由时间耗尽或玩家手动触发),进入结算
|
||||
/// </summary>
|
||||
public void EndExecution()
|
||||
{
|
||||
if (CurrentPhase != GamePhase.Execution) return;
|
||||
|
||||
CurrentPhase = GamePhase.Review;
|
||||
EmitSignal(SignalName.PhaseChanged, (int)CurrentPhase);
|
||||
GD.Print("Phase Changed: Review");
|
||||
|
||||
PerformReview();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 执行结算逻辑,并准备下一回合
|
||||
/// </summary>
|
||||
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.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始新的回合
|
||||
/// </summary>
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
||||
40
scripts/Models/MentorModel.cs
Normal file
40
scripts/Models/MentorModel.cs
Normal file
@ -0,0 +1,40 @@
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 导师数据模型 (MentorModel)
|
||||
/// 玩家的数值状态。
|
||||
/// </summary>
|
||||
public class MentorModel
|
||||
{
|
||||
public enum MentorModeType
|
||||
{
|
||||
Worker,
|
||||
Manager
|
||||
}
|
||||
/// <summary>
|
||||
/// 精力值 (Energy)
|
||||
/// 用于释放技能(画饼、PUA、甚至亲自写代码)。
|
||||
/// 每回合恢复。
|
||||
/// </summary>
|
||||
public StatusValue Energy { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 经费 (Money/Funds)
|
||||
/// 单位:元。用于发工资、买设备。
|
||||
/// </summary>
|
||||
public int Money { get; set; } = 50000;
|
||||
|
||||
/// <summary>
|
||||
/// 学术声望 (Reputation)
|
||||
/// 影响招生质量、项目申请成功率。
|
||||
/// </summary>
|
||||
public int Reputation { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 算力/数据资源 (ResearchPoints)
|
||||
/// 用于攻克高难度 AI 课题。
|
||||
/// </summary>
|
||||
public int ResearchPoints { get; set; } = 0;
|
||||
|
||||
public MentorModeType Mode { get; set; } = MentorModeType.Worker;
|
||||
}
|
||||
1
scripts/Models/MentorModel.cs.uid
Normal file
1
scripts/Models/MentorModel.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://dyehdtnucytg2
|
||||
122
scripts/Models/PropertyValue.cs
Normal file
122
scripts/Models/PropertyValue.cs
Normal file
@ -0,0 +1,122 @@
|
||||
using System;
|
||||
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 属性值类型
|
||||
/// 封装了整型数值,提供最大值限制(100)和显示转换。
|
||||
/// </summary>
|
||||
public class PropertyValue
|
||||
{
|
||||
public const int Min = 0;
|
||||
public const int Max = 100;
|
||||
|
||||
private float _value;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置当前值。
|
||||
/// 设置时会自动限制在 [Min, Max] 范围内。
|
||||
/// </summary>
|
||||
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) { }
|
||||
|
||||
/// <summary>
|
||||
/// 获取显示值 (Value / 100.0f)
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
1
scripts/Models/PropertyValue.cs.uid
Normal file
1
scripts/Models/PropertyValue.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://l58i2kmspq7c
|
||||
101
scripts/Models/StatusValue.cs
Normal file
101
scripts/Models/StatusValue.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using System;
|
||||
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 状态值 (StatusValue)
|
||||
/// 维护当前状态值以及上限和下限阈值。
|
||||
/// </summary>
|
||||
public class StatusValue
|
||||
{
|
||||
private PropertyValue _current;
|
||||
private PropertyValue _upperThreshold;
|
||||
private PropertyValue _lowerThreshold;
|
||||
|
||||
/// <summary>
|
||||
/// 当 Current >= UpperThreshold 时触发此事件
|
||||
/// </summary>
|
||||
public event Action OnUpperThresholdReached;
|
||||
|
||||
/// <summary>
|
||||
/// 当 Current <= LowerThreshold 时触发此事件
|
||||
/// </summary>
|
||||
public event Action OnLowerThresholdReached;
|
||||
|
||||
/// <summary>
|
||||
/// 当前状态值
|
||||
/// 修改时会自动检测阈值。
|
||||
/// </summary>
|
||||
public PropertyValue Current
|
||||
{
|
||||
get => _current;
|
||||
set
|
||||
{
|
||||
_current = value;
|
||||
CheckThresholds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 上限阈值
|
||||
/// </summary>
|
||||
public PropertyValue UpperThreshold
|
||||
{
|
||||
get => _upperThreshold;
|
||||
set
|
||||
{
|
||||
_upperThreshold = value;
|
||||
CheckThresholds();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下限阈值
|
||||
/// </summary>
|
||||
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
|
||||
}
|
||||
}
|
||||
1
scripts/Models/StatusValue.cs.uid
Normal file
1
scripts/Models/StatusValue.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://no453n0ubri1
|
||||
63
scripts/Models/StudentModel.cs
Normal file
63
scripts/Models/StudentModel.cs
Normal file
@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 学生数据模型 (StudentModel)
|
||||
/// 包含学生的数值、状态和特质。
|
||||
/// 与 Godot 的 Node (View) 分离,便于序列化和逻辑处理。
|
||||
/// </summary>
|
||||
public class StudentModel: UnitModel
|
||||
{
|
||||
public enum StudentType
|
||||
{
|
||||
MasterCandidate,
|
||||
DoctorCandidate
|
||||
}
|
||||
|
||||
// --- 静态属性 (Property) ---
|
||||
/// <summary>
|
||||
/// 学生类型
|
||||
/// </summary>
|
||||
public StudentType Type { get; private set; }
|
||||
|
||||
// --- 动态状态 (Status) ---
|
||||
|
||||
/// <summary>
|
||||
/// 体力 (Stamina)
|
||||
/// 范围 0-100。工作消耗体力,休息恢复。体力过低效率下降。
|
||||
/// </summary>
|
||||
public StatusValue Stamina { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 忠诚度 (Loyalty)
|
||||
/// 范围 0-100。过低可能跳槽或举报。
|
||||
/// </summary>
|
||||
public StatusValue Loyalty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 年级
|
||||
/// </summary>
|
||||
public StatusValue Grade { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 记录对每个 Task 的贡献量,用于署名分配
|
||||
/// </summary>
|
||||
public Dictionary<Guid, PropertyValue> Contributions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 特质列表 (如 "DDL战士", "卷王")
|
||||
/// </summary>
|
||||
public List<string> 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);
|
||||
}
|
||||
}
|
||||
|
||||
1
scripts/Models/StudentModel.cs.uid
Normal file
1
scripts/Models/StudentModel.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://eoh7yvyhct5d
|
||||
97
scripts/Models/Task.cs
Normal file
97
scripts/Models/Task.cs
Normal file
@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 任务类型枚举
|
||||
/// </summary>
|
||||
public enum TaskType
|
||||
{
|
||||
Paper, // 论文:重学术(Intelligence) + 表达(Expression)
|
||||
Project, // 项目:重工程(Strength) + 学术(Intelligence)
|
||||
Admin // 杂务:消耗体力,低收益,但必须做
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 任务 (Task)
|
||||
/// 核心游戏对象之一,相当于地图上的“怪物”。
|
||||
/// 学生需要“攻击”任务(消耗工作量)来完成它。
|
||||
/// </summary>
|
||||
public class Task
|
||||
{
|
||||
public Guid Id { get; private set; } = Guid.NewGuid();
|
||||
|
||||
/// <summary>
|
||||
/// 任务名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务类型
|
||||
/// </summary>
|
||||
public TaskType Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 总工作量 (HP)
|
||||
/// </summary>
|
||||
public float TotalWorkload { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前进度
|
||||
/// </summary>
|
||||
public float CurrentProgress { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 难度系数 (Defense)
|
||||
/// 影响学生攻克该任务的效率。若学生能力低于难度,效率会大幅下降。
|
||||
/// </summary>
|
||||
public float Difficulty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 截止日期 (剩余回合数)
|
||||
/// 归零时如果未完成,触发失败惩罚。
|
||||
/// </summary>
|
||||
public int Deadline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 奖励:经费
|
||||
/// </summary>
|
||||
public int RewardMoney { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 奖励:声望
|
||||
/// </summary>
|
||||
public int RewardReputation { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 任务是否已完成
|
||||
/// </summary>
|
||||
public bool IsCompleted => CurrentProgress >= TotalWorkload;
|
||||
|
||||
/// <summary>
|
||||
/// 任务是否已失败(超时未完成)
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 增加进度
|
||||
/// </summary>
|
||||
/// <param name="amount">工作量数值</param>
|
||||
public void AddProgress(float amount)
|
||||
{
|
||||
CurrentProgress += amount;
|
||||
if (CurrentProgress > TotalWorkload) CurrentProgress = TotalWorkload;
|
||||
}
|
||||
}
|
||||
|
||||
1
scripts/Models/Task.cs.uid
Normal file
1
scripts/Models/Task.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://052kca2012sn
|
||||
78
scripts/Models/UnitModel.cs
Normal file
78
scripts/Models/UnitModel.cs
Normal file
@ -0,0 +1,78 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace Models;
|
||||
|
||||
/// <summary>
|
||||
/// 所有角色的基类,无论是导师、学生还是博后。
|
||||
/// </summary>
|
||||
public class UnitModel
|
||||
{
|
||||
public Guid Id { get; private set; } = Guid.NewGuid();
|
||||
public string Name { get; set; }
|
||||
|
||||
// 基础属性
|
||||
|
||||
/// <summary>
|
||||
/// 学术能力,影响科研进度
|
||||
/// </summary>
|
||||
public PropertyValue Academic {get; set;}
|
||||
/// <summary>
|
||||
/// 工程能力,影响实验进度
|
||||
/// </summary>
|
||||
public PropertyValue Engineering {get; set;}
|
||||
/// <summary>
|
||||
/// 写作能力,影响论文发表
|
||||
/// </summary>
|
||||
public PropertyValue Writing {get; set;}
|
||||
/// <summary>
|
||||
/// 财务能力,影响资金相关任务
|
||||
/// </summary>
|
||||
public PropertyValue Financial {get; set;}
|
||||
/// <summary>
|
||||
/// 社交能力
|
||||
/// </summary>
|
||||
public PropertyValue Social {get; set;}
|
||||
/// <summary>
|
||||
/// 行动力,影响各种行为的效率和能动性
|
||||
/// </summary>
|
||||
public PropertyValue Activation {get; set;}
|
||||
|
||||
// 状态属性
|
||||
|
||||
/// <summary>
|
||||
/// 压力值
|
||||
/// </summary>
|
||||
public StatusValue Stress {get; set;}
|
||||
/// <summary>
|
||||
/// 精神值 (Sanity) / 抗压能力
|
||||
/// 范围 0-100。过低会导致崩溃(Breakdown)。
|
||||
/// </summary>
|
||||
public StatusValue Sanity { get; set; }
|
||||
/// <summary>
|
||||
/// 情绪值,影响工作效率
|
||||
/// </summary>
|
||||
public PropertyValue Mood {get; set;}
|
||||
/// <summary>
|
||||
/// 移动速度
|
||||
/// </summary>
|
||||
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);
|
||||
}
|
||||
}
|
||||
1
scripts/Models/UnitModel.cs.uid
Normal file
1
scripts/Models/UnitModel.cs.uid
Normal file
@ -0,0 +1 @@
|
||||
uid://hremnrofal6l
|
||||
@ -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<Vector2I> PathToGo = new();
|
||||
@ -140,7 +151,15 @@ public partial class Student : CharacterBody2D
|
||||
animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
|
||||
animationPlayer.Play("idle_front");
|
||||
var name_test = GetNode<StudentName>("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<Vector2I> path)
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="docs\design.md" />
|
||||
<Content Include="docs\detail_design.md" />
|
||||
<Content Include="docs\mvp_design.md" />
|
||||
<Content Include="README.md" />
|
||||
</ItemGroup>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user