Player movement. To Fix: player out of area.

This commit is contained in:
wjsjwr 2025-12-27 23:00:14 +08:00
parent f3a4e31f31
commit bce6fffc3e
20 changed files with 635 additions and 188 deletions

View File

@ -11,7 +11,7 @@ config_version=5
[application]
config/name="最强导师"
run/main_scene="uid://bmxk4pi4sd1rd"
run/main_scene="uid://b0cu4fa7vohmw"
config/features=PackedStringArray("4.5", "C#", "GL Compatibility")
config/icon="res://icon.svg"

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 178 KiB

After

Width:  |  Height:  |  Size: 177 KiB

View File

@ -1,5 +1,6 @@
using Godot;
using System;
using System.Collections.Generic;
public partial class CampusController : Node2D
{
@ -8,6 +9,16 @@ public partial class CampusController : Node2D
private Button _taskToggle;
private Button _logToggle;
[Export] public PackedScene StudentScene { get; set; }
[Export] public int StudentCount { get; set; } = 6;
[Export] public float CoverageStep { get; set; } = 48.0f;
[Export] public int MaxCoveragePoints { get; set; } = 200;
private NavigationRegion2D _navigationRegion;
private Node2D _studentsRoot;
private readonly List<Vector2> _coveragePoints = new();
private bool _spawnPending = true;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
@ -24,11 +35,24 @@ public partial class CampusController : Node2D
_taskToggle.Toggled += OnTaskToggled;
_logToggle.Toggled += OnLogToggled;
// 导航区域与学生容器初始化
_navigationRegion = GetNodeOrNull<NavigationRegion2D>("Sprite2D/NavigationRegion2D");
_studentsRoot = GetNodeOrNull<Node2D>("Students");
if (_studentsRoot == null)
{
_studentsRoot = new Node2D { Name = "Students" };
AddChild(_studentsRoot);
}
// 等待导航地图同步完成后再生成学生
_spawnPending = true;
}
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
TrySpawnStudents();
}
private void OnTaskToggled(bool pressed)
@ -61,4 +85,158 @@ public partial class CampusController : Node2D
tween.TweenCallback(Callable.From(() => container.Visible = false));
}
}
}
private void TrySpawnStudents()
{
if (!_spawnPending)
{
return;
}
// 已生成过学生则不重复生成
if (_studentsRoot != null && _studentsRoot.GetChildCount() > 0)
{
_spawnPending = false;
return;
}
if (StudentScene == null)
{
StudentScene = ResourceLoader.Load<PackedScene>("res://scenes/student_16_native.tscn");
}
if (_navigationRegion == null || _navigationRegion.NavigationPolygon == null)
{
GD.PushWarning("校园导航区域未配置或缺失导航多边形,无法生成巡游学生。");
_spawnPending = false;
return;
}
// 导航地图可能还未就绪,需要等待同步完成后再采样
var map = GetNavigationMap();
if (!map.IsValid)
{
return;
}
// 强制刷新一次导航数据,确保首帧同步
NavigationServer2D.MapForceUpdate(map);
if (NavigationServer2D.MapGetIterationId(map) == 0)
{
return;
}
SpawnStudents(map);
_spawnPending = false;
}
private void SpawnStudents(Rid map)
{
_coveragePoints.Clear();
_coveragePoints.AddRange(BuildCoveragePoints(map));
if (_coveragePoints.Count == 0)
{
GD.PushWarning("未采样到可行走区域,跳过学生生成。");
return;
}
for (int i = 0; i < StudentCount; i++)
{
var instance = StudentScene.Instantiate();
if (instance is not CampusStudent student)
{
GD.PushWarning("student_16_native.tscn 需要挂载 CampusStudent 脚本。");
instance.QueueFree();
continue;
}
_studentsRoot.AddChild(student);
student.Name = $"CampusStudent_{i + 1}";
// 随机放置在可行走区域,并设置不同的巡游起点
var randomIndex = GD.RandRange(0, _coveragePoints.Count - 1);
student.GlobalPosition = _coveragePoints[randomIndex];
student.ConfigurePatrol(_coveragePoints, i * 7);
}
}
private List<Vector2> BuildCoveragePoints(Rid map)
{
var points = new List<Vector2>();
var polygon = _navigationRegion.NavigationPolygon;
if (polygon == null || polygon.Vertices.Length == 0)
{
return points;
}
// 根据导航多边形顶点计算采样范围
var min = polygon.Vertices[0];
var max = polygon.Vertices[0];
foreach (var v in polygon.Vertices)
{
min = new Vector2(Mathf.Min(min.X, v.X), Mathf.Min(min.Y, v.Y));
max = new Vector2(Mathf.Max(max.X, v.X), Mathf.Max(max.Y, v.Y));
}
var step = Mathf.Max(8.0f, CoverageStep);
var minDistance = step * 0.45f;
for (float x = min.X; x <= max.X; x += step)
{
for (float y = min.Y; y <= max.Y; y += step)
{
var local = new Vector2(x, y);
var global = _navigationRegion.ToGlobal(local);
var closest = NavigationServer2D.MapGetClosestPoint(map, global);
if (closest.DistanceTo(global) > minDistance)
{
continue;
}
if (!HasNearbyPoint(points, closest, minDistance))
{
points.Add(closest);
if (points.Count >= MaxCoveragePoints)
{
return points;
}
}
}
}
// 兜底:至少给一个可行走点
if (points.Count == 0)
{
var centerLocal = (min + max) * 0.5f;
var centerGlobal = _navigationRegion.ToGlobal(centerLocal);
points.Add(NavigationServer2D.MapGetClosestPoint(map, centerGlobal));
}
return points;
}
private Rid GetNavigationMap()
{
var map = NavigationServer2D.RegionGetMap(_navigationRegion.GetRid());
if (!map.IsValid)
{
var world = GetWorld2D();
if (world != null)
{
map = world.NavigationMap;
}
}
return map;
}
private static bool HasNearbyPoint(List<Vector2> points, Vector2 candidate, float minDistance)
{
for (int i = 0; i < points.Count; i++)
{
if (points[i].DistanceTo(candidate) <= minDistance)
{
return true;
}
}
return false;
}
}

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=8 format=3 uid="uid://b0cu4fa7vohmw"]
[gd_scene load_steps=9 format=3 uid="uid://b0cu4fa7vohmw"]
[ext_resource type="Script" uid="uid://ew4ig6hnrsau" path="res://scenes/CampusController.cs" id="1_controller"]
[ext_resource type="PackedScene" uid="uid://cf6b1t8pujosf" path="res://scenes/ui-elements/log_panel.tscn" id="1_hi2p7"]
@ -6,6 +6,15 @@
[ext_resource type="PackedScene" uid="uid://db2qcx61nc0q4" path="res://scenes/ui-elements/top-bar.tscn" id="2_p4tmp"]
[ext_resource type="PackedScene" uid="uid://drmjsqoy8htc8" path="res://scenes/ui-elements/task_list.tscn" id="3_4gjr3"]
[sub_resource type="NavigationPolygon" id="NavigationPolygon_8u8vn"]
vertices = PackedVector2Array(960, 544, 0, 544, 416, 512, 464, 512, 384, 512, 384, 464, 176, 496, 304, 464, 144, 496, 200, 352, 200, 264, 232, 304, 232, 464, 232, 288, 144, 208, 144, 192, 160, 192, 160, 208, 240, 208, 240, 16, 272, 16, 272, 232, 432, 232, 432, 192, 448, 192, 448, 232, 608, 232, 608, 16, 640, 16, 640, 240, 704, 240, 704, 192, 728, 192, 728, 168, 760, 168, 760, 192, 768, 192, 768, 16, 800, 16, 800, 224, 840, 224, 840, 192, 856, 192, 856, 224, 864, 224, 864, 288, 832, 288, 832, 224, 800, 288, 912, 304, 912, 288, 936, 288, 952, 336, 936, 184, 952, 184, 832, 336, 832, 304, 832, 512, 800, 512, 576, 288, 576, 304, 544, 304, 544, 288, 960, 512, 120, 360, 128, 360, 128, 400, 192, 400, 192, 352, 288, 464, 288, 448, 304, 448, 176, 464, 144, 464, 0, 496, 96, 496, 96, 288, 120, 264, 0, 288, 0, 0, 32, 0, 32, 208, 416, 288, 464, 288)
polygons = Array[PackedInt32Array]([PackedInt32Array(0, 1, 2, 3), PackedInt32Array(4, 2, 1), PackedInt32Array(5, 4, 1, 6, 7), PackedInt32Array(8, 6, 1), PackedInt32Array(9, 10, 11, 12), PackedInt32Array(13, 11, 10), PackedInt32Array(14, 15, 16, 17), PackedInt32Array(18, 19, 20, 21), PackedInt32Array(22, 23, 24, 25), PackedInt32Array(26, 27, 28, 29), PackedInt32Array(30, 31, 32), PackedInt32Array(32, 33, 34, 35), PackedInt32Array(36, 37, 38, 39), PackedInt32Array(40, 41, 42, 43), PackedInt32Array(43, 44, 45, 46), PackedInt32Array(40, 43, 46), PackedInt32Array(47, 40, 46), PackedInt32Array(39, 47, 46, 48), PackedInt32Array(49, 50, 51, 52), PackedInt32Array(51, 53, 54, 52), PackedInt32Array(49, 52, 55, 56), PackedInt32Array(55, 57, 58, 48), PackedInt32Array(56, 55, 48), PackedInt32Array(46, 56, 48), PackedInt32Array(39, 48, 59, 30), PackedInt32Array(59, 60, 61, 62), PackedInt32Array(57, 63, 0), PackedInt32Array(64, 65, 66), PackedInt32Array(67, 68, 9, 12), PackedInt32Array(69, 70, 71, 7), PackedInt32Array(69, 7, 6), PackedInt32Array(12, 69, 6), PackedInt32Array(12, 6, 72, 67), PackedInt32Array(66, 67, 72, 73), PackedInt32Array(1, 74, 75), PackedInt32Array(8, 1, 75), PackedInt32Array(73, 8, 75, 76, 66), PackedInt32Array(64, 66, 76), PackedInt32Array(77, 64, 76), PackedInt32Array(78, 79, 80, 81), PackedInt32Array(76, 78, 81, 14, 77), PackedInt32Array(10, 77, 14, 17), PackedInt32Array(10, 17, 18, 21, 13), PackedInt32Array(82, 13, 21, 22), PackedInt32Array(82, 22, 25), PackedInt32Array(30, 32, 35, 39), PackedInt32Array(82, 25, 26, 83), PackedInt32Array(35, 36, 39), PackedInt32Array(29, 30, 59), PackedInt32Array(26, 29, 59, 62), PackedInt32Array(26, 62, 83), PackedInt32Array(82, 83, 3, 2), PackedInt32Array(0, 3, 58), PackedInt32Array(0, 58, 57)])
outlines = Array[PackedVector2Array]([PackedVector2Array(0, 0, 32, 0, 32, 208, 144, 208, 144, 192, 160, 192, 160, 208, 240, 208, 240, 16, 272, 16, 272, 232, 432, 232, 432, 192, 448, 192, 448, 232, 608, 232, 608, 16, 640, 16, 640, 240, 704, 240, 704, 192, 728, 192, 728, 168, 760, 168, 760, 192, 768, 192, 768, 16, 800, 16, 800, 224, 832, 224, 840, 224, 840, 192, 856, 192, 856, 224, 864, 224, 864, 288, 832, 288, 832, 304, 912, 304, 912, 288, 936, 288, 936, 184, 952, 184, 952, 336, 832, 336, 832, 512, 960, 512, 960, 544, 0, 544, 0, 496, 96, 496, 96, 288, 0, 288), PackedVector2Array(144, 496, 176, 496, 176, 464, 144, 464), PackedVector2Array(128, 400, 192, 400, 192, 352, 200, 352, 200, 264, 120, 264, 120, 360, 128, 360), PackedVector2Array(232, 304, 232, 464, 288, 464, 288, 448, 304, 448, 304, 464, 384, 464, 384, 512, 416, 512, 416, 288, 232, 288), PackedVector2Array(464, 288, 464, 512, 800, 512, 800, 288, 576, 288, 576, 304, 544, 304, 544, 288), PackedVector2Array(144, 416, 176, 416, 176, 448, 144, 448)])
parsed_geometry_type = 1
parsed_collision_mask = 4294967294
source_geometry_mode = 1
agent_radius = 8.0
[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_4gjr3"]
texture = ExtResource("1_p4tmp")
use_texture_padding = false
@ -2000,16 +2009,22 @@ script = ExtResource("1_controller")
texture = ExtResource("1_p4tmp")
centered = false
[node name="NavigationRegion2D" type="NavigationRegion2D" parent="Sprite2D"]
navigation_polygon = SubResource("NavigationPolygon_8u8vn")
[node name="Log" parent="." instance=ExtResource("1_hi2p7")]
visible = false
offset_left = 655.0
offset_top = 375.0
offset_right = 955.0
offset_bottom = 535.0
[node name="TopBar" parent="." instance=ExtResource("2_p4tmp")]
visible = false
offset_bottom = 55.0
[node name="Task" parent="." instance=ExtResource("3_4gjr3")]
visible = false
offset_left = 4.0
offset_top = 216.0
offset_right = 305.0

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=23 format=3 uid="uid://bmxk4pi4sd1rd"]
[ext_resource type="Script" uid="uid://bcy30mq13r02a" path="res://scripts/Student.cs" id="1_oesea"]
[ext_resource type="Script" uid="uid://d2m5sak3n7q1s" path="res://scripts/CampusStudent.cs" id="1_oesea"]
[ext_resource type="Texture2D" uid="uid://ckjn1gxbn26iq" path="res://resources/characters/bodies/Body_01.png" id="3_jhea4"]
[ext_resource type="Script" uid="uid://bp2483mr5lay" path="res://scripts/StudentName.cs" id="8_kvqca"]
[ext_resource type="Texture2D" uid="uid://bvngikeasxn3n" path="res://resources/characters/accessories/Accessory_06_Policeman_Hat_01.png" id="30_npp82"]
@ -10,7 +10,7 @@
[ext_resource type="Texture2D" uid="uid://bscmf27jf2qf0" path="res://resources/characters/smartphones/Smartphone_1.png" id="435_7vwql"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_opr6h"]
size = Vector2(16, 32)
size = Vector2(16, 16)
[sub_resource type="Animation" id="Animation_f0f87"]
length = 0.001
@ -877,10 +877,8 @@ _data = {
[node name="Student" type="CharacterBody2D"]
z_index = 2
script = ExtResource("1_oesea")
Use16x16Sprites = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0, -8)
shape = SubResource("RectangleShape2D_opr6h")
[node name="parts" type="Node2D" parent="."]
@ -935,3 +933,11 @@ autoplay = "RESET"
[node name="StudentName" type="Node" parent="."]
script = ExtResource("8_kvqca")
[node name="NavigationAgent2D" type="NavigationAgent2D" parent="."]
path_desired_distance = 4.0
target_desired_distance = 4.0
path_max_distance = 5000.0
path_postprocessing = 1
radius = 8.0
debug_enabled = true

246
scripts/CampusStudent.cs Normal file
View File

@ -0,0 +1,246 @@
using System.Collections.Generic;
using System.Diagnostics;
using Godot;
public partial class CampusStudent : CharacterBody2D
{
private Sprite2D _accessory;
private AnimationPlayer _animationPlayer;
private Sprite2D _body;
private Sprite2D _eye;
private Sprite2D _hairstyle;
private double _lastDelta;
private FacingDirection _lastFacing = FacingDirection.Down;
private Vector2 _lastPosition;
private NavigationAgent2D _navigationAgent;
private Sprite2D _outfit;
private bool _patrolConfigured;
private int _patrolIndex;
private List<Vector2> _patrolPoints = new();
private Sprite2D _smartphone;
private float _stuckTimer;
[Export] public float MoveSpeed { get; set; } = 60.0f;
[Export] public float TargetReachDistance { get; set; } = 6.0f;
[Export] public bool Use16X16Sprites { get; set; } = true;
[Export] public bool EnableAvoidance { get; set; } = true;
[Export] public float StuckRepathSeconds { get; set; } = 0.6f;
[Export] public float StuckDistanceEpsilon { get; set; } = 2.0f;
public override void _Ready()
{
_navigationAgent = GetNodeOrNull<NavigationAgent2D>("NavigationAgent2D");
_animationPlayer = GetNodeOrNull<AnimationPlayer>("AnimationPlayer");
CacheSprites();
if (_navigationAgent != null)
{
// 让寻路点更“贴近目标”,避免走到边缘时抖动
_navigationAgent.PathDesiredDistance = TargetReachDistance;
_navigationAgent.TargetDesiredDistance = TargetReachDistance;
_navigationAgent.AvoidanceEnabled = EnableAvoidance;
if (EnableAvoidance)
// 开启避让时使用安全速度回调进行移动
_navigationAgent.VelocityComputed += OnVelocityComputed;
if (_patrolConfigured) AdvanceTarget();
}
PlayIdleAnimation();
_lastPosition = GlobalPosition;
}
public override void _PhysicsProcess(double delta)
{
_lastDelta = delta;
if (_navigationAgent == null || _patrolPoints.Count == 0)
{
PlayIdleAnimation();
return;
}
// 到达目标点或无路可走时,切换到下一个巡游点
if (_navigationAgent.IsNavigationFinished() || _navigationAgent.DistanceToTarget() <= TargetReachDistance)
AdvanceTarget();
var nextPosition = _navigationAgent.GetNextPathPosition();
var toNext = nextPosition - GlobalPosition;
if (toNext.LengthSquared() < 0.01f)
{
if (!EnableAvoidance)
{
Velocity = Vector2.Zero;
MoveAndSlide();
}
PlayIdleAnimation();
UpdateStuckTimer(delta);
return;
}
var direction = toNext.Normalized();
var desiredVelocity = direction * MoveSpeed;
if (EnableAvoidance)
{
// 交给导航系统做群体避让
_navigationAgent.Velocity = desiredVelocity;
}
else
{
// 未启用避让时直接移动
Velocity = desiredVelocity;
MoveAndSlide();
UpdateFacingAnimation(Velocity);
UpdateStuckTimer(delta);
}
}
public void ConfigurePatrol(List<Vector2> points, int startIndex)
{
_patrolPoints = points ?? new List<Vector2>();
if (_patrolPoints.Count == 0) return;
_patrolIndex = (startIndex % _patrolPoints.Count + _patrolPoints.Count) % _patrolPoints.Count;
_patrolConfigured = true;
ApplyRandomTheme();
if (_navigationAgent != null) AdvanceTarget();
}
public void ApplyRandomTheme()
{
// 随机替换身体与配件贴图,形成不同主题外观
if (_body == null) CacheSprites();
Debug.Assert(_body != null, nameof(_body) + " != null");
_body.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Body, Use16X16Sprites));
_hairstyle.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Hair, Use16X16Sprites));
_outfit.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Outfit, Use16X16Sprites));
_eye.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Eye, Use16X16Sprites));
_accessory.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Accessory, Use16X16Sprites));
_smartphone.Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Phone, Use16X16Sprites));
}
private void CacheSprites()
{
// 缓存子节点引用,避免每帧查找
_body = GetNode<Sprite2D>("parts/body");
_hairstyle = GetNode<Sprite2D>("parts/hairstyle");
_outfit = GetNode<Sprite2D>("parts/outfit");
_eye = GetNode<Sprite2D>("parts/eye");
_accessory = GetNode<Sprite2D>("parts/accessory");
_smartphone = GetNode<Sprite2D>("parts/smartphone");
}
private void AdvanceTarget()
{
if (_patrolPoints.Count == 0 || _navigationAgent == null) return;
// 避免当前点过近导致原地抖动,最多尝试一轮
for (var i = 0; i < _patrolPoints.Count; i++)
{
var target = _patrolPoints[_patrolIndex];
_patrolIndex = (_patrolIndex + 1) % _patrolPoints.Count;
if (GlobalPosition.DistanceTo(target) > TargetReachDistance * 1.5f)
{
_navigationAgent.TargetPosition = target;
return;
}
}
_navigationAgent.TargetPosition = _patrolPoints[_patrolIndex];
}
private void OnVelocityComputed(Vector2 safeVelocity)
{
// 使用安全速度移动,避免与其它角色硬碰硬卡住
Velocity = safeVelocity;
MoveAndSlide();
UpdateFacingAnimation(Velocity);
UpdateStuckTimer(_lastDelta);
}
private void UpdateStuckTimer(double delta)
{
// 若短时间内几乎没有位移,则换一个目标点脱困
if (GlobalPosition.DistanceTo(_lastPosition) <= StuckDistanceEpsilon)
_stuckTimer += (float)delta;
else
_stuckTimer = 0.0f;
_lastPosition = GlobalPosition;
if (_stuckTimer >= StuckRepathSeconds)
{
_stuckTimer = 0.0f;
AdvanceTarget();
}
}
private void UpdateFacingAnimation(Vector2 velocity)
{
if (velocity.LengthSquared() < 0.01f)
{
PlayIdleAnimation();
return;
}
if (Mathf.Abs(velocity.X) >= Mathf.Abs(velocity.Y))
_lastFacing = velocity.X >= 0 ? FacingDirection.Right : FacingDirection.Left;
else
_lastFacing = velocity.Y >= 0 ? FacingDirection.Down : FacingDirection.Up;
switch (_lastFacing)
{
case FacingDirection.Left:
PlayAnimation("walk_left");
break;
case FacingDirection.Right:
PlayAnimation("walk_right");
break;
case FacingDirection.Up:
PlayAnimation("walk_up");
break;
case FacingDirection.Down:
PlayAnimation("walk_down");
break;
}
}
private void PlayIdleAnimation()
{
switch (_lastFacing)
{
case FacingDirection.Left:
PlayAnimation("idle_left");
break;
case FacingDirection.Right:
PlayAnimation("idle_right");
break;
case FacingDirection.Up:
PlayAnimation("idle_back");
break;
case FacingDirection.Down:
PlayAnimation("idle_front");
break;
}
}
private void PlayAnimation(string animationName)
{
if (_animationPlayer == null) return;
if (_animationPlayer.CurrentAnimation != animationName) _animationPlayer.Play(animationName);
}
private enum FacingDirection
{
Up,
Down,
Left,
Right
}
}

View File

@ -0,0 +1 @@
uid://d2m5r9k3n7q1s

View File

@ -86,7 +86,7 @@ public partial class Cube : StaticBody2D, ITileDraggable
}
private readonly Guid _id = Guid.NewGuid();
public Guid ID => _id;
public Guid Id => _id;
public Vector2I TilePosition { get; set; } = new Vector2I(5,5);
private bool _isCollided = true;
@ -102,19 +102,19 @@ public partial class Cube : StaticBody2D, ITileDraggable
}
}
}
private static readonly Rect2I _tileRect = new(-1, -2, 4, 5);
public Rect2I TileRect => _tileRect;
private static readonly Rect2I tileRect = new(-1, -2, 4, 5);
public Rect2I TileRect => tileRect;
private Vector2I _mouseOffset;
public Vector2I MouseOffset => _mouseOffset;
private static readonly ITileDraggable.SpecialTile[] _specialTiles = {
private static readonly ITileDraggable.SpecialTile[] specialTiles = {
new(new Vector2I(1,-1), Lab.MapNodeType.SeatDown | Lab.MapNodeType.Walkable),
new(new Vector2I(1,2), Lab.MapNodeType.SeatUp | Lab.MapNodeType.Walkable),
};
public ITileDraggable.SpecialTile[] SpecialTiles => _specialTiles;
public ITileDraggable.SpecialTile[] SpecialTiles => specialTiles;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
@ -147,27 +147,27 @@ public partial class Cube : StaticBody2D, ITileDraggable
GlobalPosition = TilePosition * 48;
}
private int tableThemeIdx;
private int table2ThemeIdx;
private int chairThemeIdx;
private int chair2ThemeIdx;
private int equipThemeIdx;
private int equip2ThemeIdx;
private int _tableThemeIdx;
private int _table2ThemeIdx;
private int _chairThemeIdx;
private int _chair2ThemeIdx;
private int _equipThemeIdx;
private int _equip2ThemeIdx;
public void RandomChangeTheme() {
tableThemeIdx = GD.RandRange(0, tableThemes.Length-1);
chairThemeIdx = GD.RandRange(0, chairThemes.Length-1);
equipThemeIdx = GD.RandRange(0, equipThemes.Length-1);
_tableThemeIdx = GD.RandRange(0, tableThemes.Length-1);
_chairThemeIdx = GD.RandRange(0, chairThemes.Length-1);
_equipThemeIdx = GD.RandRange(0, equipThemes.Length-1);
table2ThemeIdx = GD.RandRange(0, table2Themes.Length-1);
chair2ThemeIdx = GD.RandRange(0, chair2Themes.Length-1);
equip2ThemeIdx = GD.RandRange(0, equip2Themes.Length-1);
_table2ThemeIdx = GD.RandRange(0, table2Themes.Length-1);
_chair2ThemeIdx = GD.RandRange(0, chair2Themes.Length-1);
_equip2ThemeIdx = GD.RandRange(0, equip2Themes.Length-1);
tableThemes[tableThemeIdx].Apply(GetNode<TileMapLayer>("Desk"));
chairThemes[chairThemeIdx].Apply(GetNode<TileMapLayer>("Chair"));
equipThemes[equipThemeIdx].Apply(GetNode<TileMapLayer>("Equip"));
table2Themes[table2ThemeIdx].Apply(GetNode<TileMapLayer>("Desk2"));
chair2Themes[chair2ThemeIdx].Apply(GetNode<TileMapLayer>("Chair2"));
equip2Themes[equip2ThemeIdx].Apply(GetNode<TileMapLayer>("Equip2"));
tableThemes[_tableThemeIdx].Apply(GetNode<TileMapLayer>("Desk"));
chairThemes[_chairThemeIdx].Apply(GetNode<TileMapLayer>("Chair"));
equipThemes[_equipThemeIdx].Apply(GetNode<TileMapLayer>("Equip"));
table2Themes[_table2ThemeIdx].Apply(GetNode<TileMapLayer>("Desk2"));
chair2Themes[_chair2ThemeIdx].Apply(GetNode<TileMapLayer>("Chair2"));
equip2Themes[_equip2ThemeIdx].Apply(GetNode<TileMapLayer>("Equip2"));
}
private static readonly HashSet<Vector2I> blockerTiles = new(new Vector2I[]{
new(0,0),
@ -183,15 +183,15 @@ public partial class Cube : StaticBody2D, ITileDraggable
if (blockerTiles.Contains(pos)) {
return Lab.MapNodeType.Blocker;
}
if (_specialTiles.Any(t => t.Position == pos)) {
return _specialTiles.First(t => t.Position == pos).NodeType;
if (specialTiles.Any(t => t.Position == pos)) {
return specialTiles.First(t => t.Position == pos).NodeType;
}
return Lab.MapNodeType.Walkable;
}
public void ChairFaceTo(Vector2I target, int idx) {
if (idx == 0) {
var theme = chairThemes[chairThemeIdx];
var theme = chairThemes[_chairThemeIdx];
}
}

View File

View File

@ -0,0 +1 @@
uid://odcll7t6ojce

View File

@ -10,7 +10,7 @@ public partial class GameManager : Node
/// </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");
public static readonly Resource Arrow2X = ResourceLoader.Load("res://temp_res/kenney_ui-pack-space-expansion/PNG/Extra/Double/cursor_f.png");
// --- Core Loop Definitions ---
public enum GamePhase
@ -46,7 +46,7 @@ public partial class GameManager : Node
public override void _Ready()
{
Input.SetCustomMouseCursor(Arrow2x);
Input.SetCustomMouseCursor(Arrow2X);
// MVP Initialization
InitializeGame();

View File

@ -23,5 +23,5 @@ public interface ITileDraggable {
}
Lab.MapNodeType GetTileType(Vector2I pos);
Guid ID { get; }
Guid Id { get; }
}

View File

@ -22,8 +22,8 @@ public partial class Lab : Node2D
new(39,2,1,18),
};
private readonly Dictionary<Guid, ITileDraggable> furnitureIDs = new();
public Dictionary<Guid, ITileDraggable> Furniture => furnitureIDs;
private readonly Dictionary<Guid, ITileDraggable> _furnitureIDs = new();
public Dictionary<Guid, ITileDraggable> Furniture => _furnitureIDs;
// Called when the node enters the scene tree for the first time.
public override void _Ready()
@ -38,24 +38,24 @@ public partial class Lab : Node2D
Player.Timeline.OnDayChanged += d => label.Text = d.ToLongDateString();
var table = GetNode<Cube>("Cube");
table.Draggable = true;
MoneyLabel = GetNode<Label>("BottomBar/HBoxContainer/Money");
_moneyLabel = GetNode<Label>("BottomBar/HBoxContainer/Money");
var rect = table.TileRect;
rect.Position += table.TilePosition;
furniturePlacement.Add(rect, table);
furnitureIDs.Add(table.ID, table);
_furniturePlacement.Add(rect, table);
_furnitureIDs.Add(table.Id, table);
tileMap = GetNode<TileMapLayer>("OutGround");
_tileMap = GetNode<TileMapLayer>("OutGround");
UpdateMap();
var student = GetNode<Student>("Student");
student.CubeId = table.ID;
student.CubeId = table.Id;
var r = new Rect2I(0,0,1,1);
GD.Print(H.RectHasPointInclusive(r, new Vector2I(1,0)));
}
private Label MoneyLabel = null;
private Label _moneyLabel = null;
// Called every frame. 'delta' is the elapsed time since the previous frame.
public override void _Process(double delta)
{
@ -70,7 +70,7 @@ public partial class Lab : Node2D
Player.Budget.Labor += 100;
break;
}
MoneyLabel.Text = Player.Budget.Total.ToString("N0");
_moneyLabel.Text = Player.Budget.Total.ToString("N0");
if (_isDragging && DraggingTarget != null) {
Vector2 mousePos = GetLocalMousePosition();
Vector2I cell = Point2Coord(mousePos) - DraggingTarget.MouseOffset;
@ -91,42 +91,42 @@ public partial class Lab : Node2D
public void PutDown(ITileDraggable target) {
if (target == null) return;
_isDragging = false;
furniturePlacement.Remove(furniturePlacement.First(kv => kv.Value == target).Key);
_furniturePlacement.Remove(_furniturePlacement.First(kv => kv.Value == target).Key);
var rect = target.TileRect;
rect.Position += target.TilePosition;
furniturePlacement.Add(rect, target);
_furniturePlacement.Add(rect, target);
DraggingTarget = null;
UpdateMap();
}
public ITileDraggable DraggingTarget { get; set; } = null;
public const int MAP_WIDTH = 40;
public const int MAP_HEIGHT = 21;
public const int MapWidth = 40;
public const int MapHeight = 21;
private readonly MapNodeType[,] blocks = new MapNodeType[MAP_WIDTH, MAP_HEIGHT];
private readonly MapNodeType[,] _blocks = new MapNodeType[MapWidth, MapHeight];
private Dictionary<Rect2I, ITileDraggable> furniturePlacement = new ();
private Dictionary<Rect2I, ITileDraggable> _furniturePlacement = new ();
private TileMapLayer tileMap;
private TileMapLayer _tileMap;
public void UpdateMap()
{
for (int i = 0; i < MAP_WIDTH; i++) {
for (int j = 0; j < MAP_HEIGHT; j++) {
for (int i = 0; i < MapWidth; i++) {
for (int j = 0; j < MapHeight; j++) {
Vector2I vec = new (i,j);
if (wallRectangles.Any(w => w.HasPoint(vec))) {
blocks[i, j] = MapNodeType.Wall;
} else if (furniturePlacement.Any(f => f.Key.HasPoint(vec))) {
_blocks[i, j] = MapNodeType.Wall;
} else if (_furniturePlacement.Any(f => f.Key.HasPoint(vec))) {
MapNodeType t = 0;
foreach (var kv in furniturePlacement.Where(f => f.Key.HasPoint(vec))) {
foreach (var kv in _furniturePlacement.Where(f => f.Key.HasPoint(vec))) {
t |= kv.Value.GetTileType(vec - kv.Value.TilePosition);
}
if ((t & MapNodeType.Walkable) != 0 && (t & MapNodeType.Blocker) != 0){
t ^= MapNodeType.Walkable;
}
blocks[i ,j] = t;
_blocks[i ,j] = t;
} else {
blocks[i, j] = MapNodeType.Walkable;
_blocks[i, j] = MapNodeType.Walkable;
}
}
}
@ -138,7 +138,7 @@ public partial class Lab : Node2D
{
int x = pos.X;
int y = pos.Y;
if (x < 0 || x >= MAP_WIDTH || y < 0 || y >= MAP_HEIGHT) {
if (x < 0 || x >= MapWidth || y < 0 || y >= MapHeight) {
return false;
}
return true;
@ -151,16 +151,16 @@ public partial class Lab : Node2D
return neighbor;
}
if (IsValidPosition(new Vector2I(x-1,y)) && (blocks[x-1,y] & MapNodeType.Walkable) == MapNodeType.Walkable) {
if (IsValidPosition(new Vector2I(x-1,y)) && (_blocks[x-1,y] & MapNodeType.Walkable) == MapNodeType.Walkable) {
neighbor.Add(new Vector2I(x-1,y));
}
if (IsValidPosition(new Vector2I(x+1,y)) && (blocks[x+1,y] & MapNodeType.Walkable) == MapNodeType.Walkable) {
if (IsValidPosition(new Vector2I(x+1,y)) && (_blocks[x+1,y] & MapNodeType.Walkable) == MapNodeType.Walkable) {
neighbor.Add(new Vector2I(x+1,y));
}
if (IsValidPosition(new Vector2I(x,y-1)) && (blocks[x,y-1] & MapNodeType.Walkable) == MapNodeType.Walkable) {
if (IsValidPosition(new Vector2I(x,y-1)) && (_blocks[x,y-1] & MapNodeType.Walkable) == MapNodeType.Walkable) {
neighbor.Add(new Vector2I(x,y-1));
}
if (IsValidPosition(new Vector2I(x,y+1)) && (blocks[x,y+1] & MapNodeType.Walkable) == MapNodeType.Walkable) {
if (IsValidPosition(new Vector2I(x,y+1)) && (_blocks[x,y+1] & MapNodeType.Walkable) == MapNodeType.Walkable) {
neighbor.Add(new Vector2I(x,y+1));
}
return neighbor;
@ -168,57 +168,57 @@ public partial class Lab : Node2D
public List<Vector2I> GetShortestPath(Vector2I start, Vector2I end)
{
for (int j = 0; j < MAP_HEIGHT; j++) {
for (int j = 0; j < MapHeight; j++) {
string t = "";
for (int i = 0; i < MAP_WIDTH; i++) {
if ((blocks[i,j] & MapNodeType.SeatUp) != 0) {
for (int i = 0; i < MapWidth; i++) {
if ((_blocks[i,j] & MapNodeType.SeatUp) != 0) {
t += "U";
} else if ((blocks[i,j] & MapNodeType.SeatDown) != 0) {
} else if ((_blocks[i,j] & MapNodeType.SeatDown) != 0) {
t += "D";
} else {
t += $"{blocks[i,j].ToString()[0]}";
t += $"{_blocks[i,j].ToString()[0]}";
}
}
GD.Print(t);
}
var path = new List<Vector2I>();
if (tileMap.GetCellSourceId(start) == -1 || tileMap.GetCellSourceId(end) == -1) {
if (_tileMap.GetCellSourceId(start) == -1 || _tileMap.GetCellSourceId(end) == -1) {
return path;
}
if (start == end) {
return path;
}
GD.Print($"start = {start}, end = {end}");
static int vec2idx(Vector2I v) => v.Y * MAP_WIDTH + v.X;
static Vector2I idx2vec2(int i) => new(i % MAP_WIDTH, i / MAP_WIDTH);
static int Vec2Idx(Vector2I v) => v.Y * MapWidth + v.X;
static Vector2I Idx2Vec2(int i) => new(i % MapWidth, i / MapWidth);
HashSet<int> entriesIdx = new();
foreach (var e in GetNeighbors(end)) {
entriesIdx.Add(vec2idx(e));
entriesIdx.Add(Vec2Idx(e));
}
if (entriesIdx.Count == 0) {
return path;
}
// Use Dijkstra algorithm to find the shortest path
int[] dist = new int[MAP_WIDTH * MAP_HEIGHT];
int[] prev = new int[MAP_WIDTH * MAP_HEIGHT];
bool[] visited = new bool[MAP_WIDTH * MAP_HEIGHT];
int[] dist = new int[MapWidth * MapHeight];
int[] prev = new int[MapWidth * MapHeight];
bool[] visited = new bool[MapWidth * MapHeight];
for (int i = 0; i < dist.Length; i++) {
dist[i] = int.MaxValue;
prev[i] = -1;
visited[i] = false;
}
dist[vec2idx(start)] = 0;
dist[Vec2Idx(start)] = 0;
int answer = -1;
for (int i = 0; i < dist.Length; i++) {
int min_distance = int.MaxValue;
int minDistance = int.MaxValue;
int u = -1;
for (int j = 0; j < dist.Length; j++) {
if (!visited[j] && dist[j] <= min_distance) {
min_distance = dist[j];
if (!visited[j] && dist[j] <= minDistance) {
minDistance = dist[j];
u = j;
}
}
@ -230,10 +230,10 @@ public partial class Lab : Node2D
break;
}
visited[u] = true;
var neighbors = GetNeighbors(idx2vec2(u));
var neighbors = GetNeighbors(Idx2Vec2(u));
int alt = dist[u] + 1;
foreach (var neighbor in neighbors) {
int idx = vec2idx(neighbor);
int idx = Vec2Idx(neighbor);
if (visited[idx]) continue;
if (alt < dist[idx]) {
dist[idx] = alt;
@ -242,8 +242,8 @@ public partial class Lab : Node2D
}
}
while (answer != vec2idx(start)) {
path.Add(idx2vec2(answer));
while (answer != Vec2Idx(start)) {
path.Add(Idx2Vec2(answer));
answer = prev[answer];
}
path.Reverse();
@ -260,17 +260,17 @@ public partial class Lab : Node2D
public MapNodeType GetMapNodeTypeOfPosition(Vector2I pos) {
if (!IsValidPosition(pos)) return MapNodeType.Invalid;
return blocks[pos.X, pos.Y];
return _blocks[pos.X, pos.Y];
}
public Vector2I Point2Coord(Vector2 pos) {
return tileMap.LocalToMap(tileMap.ToLocal(pos));
return _tileMap.LocalToMap(_tileMap.ToLocal(pos));
}
public Vector2I GetFurSpecialPosition(Guid fID, int idx) {
if (!furnitureIDs.ContainsKey(fID)) return Vector2I.Zero;
if (idx < 0 || idx > furnitureIDs[fID].SpecialTiles.Length) return Vector2I.Zero;
return furnitureIDs[fID].SpecialTiles[idx].Position + furnitureIDs[fID].TilePosition;
public Vector2I GetFurSpecialPosition(Guid fId, int idx) {
if (!_furnitureIDs.ContainsKey(fId)) return Vector2I.Zero;
if (idx < 0 || idx > _furnitureIDs[fId].SpecialTiles.Length) return Vector2I.Zero;
return _furnitureIDs[fId].SpecialTiles[idx].Position + _furnitureIDs[fId].TilePosition;
}
}

View File

@ -4,9 +4,9 @@ using System.Collections.Generic;
public partial class Loader : Control
{
private ProgressBar progressBar;
private int sceneLoaded = 0;
private List<string> resToLoad = new (){
private ProgressBar _progressBar;
private int _sceneLoaded = 0;
private List<string> _resToLoad = new (){
"res://scenes/lab.tscn",
"res://scenes/player.tscn"
};
@ -14,7 +14,7 @@ public partial class Loader : Control
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
progressBar = GetNode<ProgressBar>("ProgressBar");
_progressBar = GetNode<ProgressBar>("ProgressBar");
string nextScene = GameManager.NextScene;
if (nextScene != null) {
GameManager.NextScene = "res://scenes/lab.tscn";
@ -25,8 +25,8 @@ public partial class Loader : Control
// resToLoad.AddRange(Res.Hair);
// resToLoad.AddRange(Res.Outfit);
// resToLoad.AddRange(Res.Smartphone);
ResourceLoader.LoadThreadedRequest(resToLoad[sceneLoaded]);
progressBar.MaxValue = 100 * resToLoad.Count;
ResourceLoader.LoadThreadedRequest(_resToLoad[_sceneLoaded]);
_progressBar.MaxValue = 100 * _resToLoad.Count;
SetProcess(true);
}
@ -34,22 +34,22 @@ public partial class Loader : Control
public override void _Process(double delta)
{
Godot.Collections.Array progress = new();
switch(ResourceLoader.LoadThreadedGetStatus(resToLoad[sceneLoaded], progress))
switch(ResourceLoader.LoadThreadedGetStatus(_resToLoad[_sceneLoaded], progress))
{
case ResourceLoader.ThreadLoadStatus.InProgress:
progressBar.Value = 100 * sceneLoaded + (int)((float)progress[0] * 100);
_progressBar.Value = 100 * _sceneLoaded + (int)((float)progress[0] * 100);
break;
case ResourceLoader.ThreadLoadStatus.Loaded:
sceneLoaded++;
if(sceneLoaded < resToLoad.Count) {
ResourceLoader.LoadThreadedRequest(resToLoad[sceneLoaded]);
_sceneLoaded++;
if(_sceneLoaded < _resToLoad.Count) {
ResourceLoader.LoadThreadedRequest(_resToLoad[_sceneLoaded]);
} else {
SetProcess(false);
GetTree().ChangeSceneToFile("res://scenes/lab.tscn");
}
break;
default:
GD.Print("Error loading scene: " + resToLoad[sceneLoaded]);
GD.Print("Error loading scene: " + _resToLoad[_sceneLoaded]);
break;
}
}

View File

@ -43,18 +43,18 @@ public partial class Player : Node
private Dictionary<DateOnly, HashSet<Guid>> _events;
public void Subscribe(DateOnly date, Guid eventUUID)
public void Subscribe(DateOnly date, Guid eventUuid)
{
_events ??= new Dictionary<DateOnly, HashSet<Guid>>();
if (!_events.ContainsKey(date)) _events[date] = new HashSet<Guid>();
_events[date].Add(eventUUID);
_events[date].Add(eventUuid);
}
public void Unsubscribe(DateOnly date, Guid eventUUID)
public void Unsubscribe(DateOnly date, Guid eventUuid)
{
if (_events == null) return;
if (!_events.ContainsKey(date)) return;
_events[date].Remove(eventUUID);
_events[date].Remove(eventUuid);
}
private void NextDay()
@ -69,11 +69,11 @@ public partial class Player : Node
if (_events.ContainsKey(InternalDate))
{
var events = _events[InternalDate];
foreach (var eventUUID in events)
foreach (var eventUuid in events)
{
// TODO: Trigger event
OnEventTriggered?.Invoke(InternalDate, eventUUID);
GD.Print("event triggered! eventUUID: " + eventUUID.ToString());
OnEventTriggered?.Invoke(InternalDate, eventUuid);
GD.Print("event triggered! eventUUID: " + eventUuid.ToString());
}
}
}
@ -88,7 +88,7 @@ public partial class Player : Node
InternalDate = startDate;
}
public delegate void EventTriggeredEventHandler(DateOnly date, Guid eventUUID);
public delegate void EventTriggeredEventHandler(DateOnly date, Guid eventUuid);
public event EventTriggeredEventHandler OnEventTriggered;

View File

@ -15,12 +15,12 @@ public partial class Res : Node
public enum Type
{
ACCESSORY,
BODY,
EYE,
HAIR,
OUTFIT,
PHONE
Accessory,
Body,
Eye,
Hair,
Outfit,
Phone
}
public static string GetRandom(Type resType)
@ -33,7 +33,7 @@ public partial class Res : Node
return path.Replace("_48x48_", "_").Replace("_48x48", "");
}
public static string GetRandom(Type resType, bool use16x16Sprites)
public static string GetRandom(Type resType, bool use16X16Sprites)
{
var resources = allResources[(int)resType];
if (resources == null) {
@ -42,7 +42,7 @@ public partial class Res : Node
}
int index = GD.RandRange(0, resources.Length - 1);
var path = resources[index];
if (!use16x16Sprites) return path;
if (!use16X16Sprites) return path;
var path16 = To16Path(path);
return ResourceLoader.Exists(path16) ? path16 : path;

View File

@ -9,7 +9,7 @@ public partial class Student : CharacterBody2D
{
public float Speed { get; set; } = 8.0f;
public const float JumpVelocity = -400.0f;
[Export] public bool Use16x16Sprites { get; set; } = false;
[Export] public bool Use16X16Sprites { get; set; } = false;
// --- MVP: Model Binding ---
public StudentModel Model { get; private set; }
@ -23,8 +23,8 @@ public partial class Student : CharacterBody2D
public int NextType = -1;
private Queue<Vector2I> PathToGo = new();
private AnimationPlayer animationPlayer;
private Queue<Vector2I> _pathToGo = new();
private AnimationPlayer _animationPlayer;
public enum CharacterState { Idle, Walking, Sitting, SittingDown, StandingUp }
public CharacterState State { get; set; } = CharacterState.Idle;
public enum Direction { Up, Down, Left, Right }
@ -32,27 +32,27 @@ public partial class Student : CharacterBody2D
public Queue<CharacterState> StateQueue { get; set; } = new();
private Vector2I targetSpecialPosition;
private Vector2I lastWalkablePosition;
private double duration = 0;
private Vector2I _targetSpecialPosition;
private Vector2I _lastWalkablePosition;
private double _duration = 0;
private void SitDown(double delta) {
duration += delta;
if (!(duration > 0.3)) return;
_duration += delta;
if (!(_duration > 0.3)) return;
if (TargetDirection == Direction.Up) {
}
animationPlayer.Play("idle_front");
_animationPlayer.Play("idle_front");
State = StateQueue.Dequeue();
GlobalPosition = targetSpecialPosition;
GlobalPosition = _targetSpecialPosition;
}
private void GettingUp(double delta) {
duration += delta;
if (!(duration > 0.3)) return;
_duration += delta;
if (!(_duration > 0.3)) return;
State = StateQueue.Dequeue();
GlobalPosition = lastWalkablePosition;
GlobalPosition = _lastWalkablePosition;
}
public override void _PhysicsProcess(double delta)
{
@ -64,7 +64,7 @@ public partial class Student : CharacterBody2D
}
if (StateQueue.Peek() == CharacterState.StandingUp && State == CharacterState.Sitting) {
duration = 0;
_duration = 0;
State = StateQueue.Dequeue();
return;
}
@ -77,17 +77,17 @@ public partial class Student : CharacterBody2D
// GD.Print($"{State} -> Empty");
}
if (PathToGo.Count == 0)
if (_pathToGo.Count == 0)
{
if (State != CharacterState.Walking) return;
if (StateQueue.Count > 0) {
if (StateQueue.Peek() == CharacterState.SittingDown) {
duration = 0;
_duration = 0;
}
State = StateQueue.Dequeue();
}
if (State == CharacterState.Idle) {
animationPlayer.Play("idle_front");
_animationPlayer.Play("idle_front");
}
return;// No path to follow.
}
@ -95,10 +95,10 @@ public partial class Student : CharacterBody2D
if (State != CharacterState.Walking) return;
Vector2 velocity = new();
var nextPoint = PathToGo.Peek();
var nextPoint = _pathToGo.Peek();
if ((int)GlobalPosition.X == nextPoint.X && (int)GlobalPosition.Y == nextPoint.Y)
{
PathToGo.Dequeue();
_pathToGo.Dequeue();
return;
}
@ -109,10 +109,10 @@ public partial class Student : CharacterBody2D
velocity.Y = Speed;
if (GlobalPosition.Y > nextPoint.Y)
{
animationPlayer.Play("walk_up");
_animationPlayer.Play("walk_up");
velocity.Y = -velocity.Y;
} else {
animationPlayer.Play("walk_down");
_animationPlayer.Play("walk_down");
}
}
else if ((int)GlobalPosition.Y == nextPoint.Y)
@ -123,10 +123,10 @@ public partial class Student : CharacterBody2D
if (GlobalPosition.X > nextPoint.X)
{
animationPlayer.Play("walk_left");
_animationPlayer.Play("walk_left");
velocity.X = -velocity.X;
} else {
animationPlayer.Play("walk_right");
_animationPlayer.Play("walk_right");
}
}
GlobalPosition = GlobalPosition with
@ -149,17 +149,17 @@ public partial class Student : CharacterBody2D
// bb.BindVarToProperty("Stayed", this, "Speed");
// GD.Print(bb.GetVar("Stayed"));
// GD.Print($"Speed: {Speed}");
animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
animationPlayer.Play("idle_front");
var name_test = GetNode<StudentName>("StudentName");
_animationPlayer = GetNode<AnimationPlayer>("AnimationPlayer");
_animationPlayer.Play("idle_front");
var nameTest = GetNode<StudentName>("StudentName");
// MVP: Initialize Model if null
if (Model == null)
{
Model = new StudentModel(name_test.GenerateName());
Model = new StudentModel(nameTest.GenerateName());
GD.Print($"[Auto-Init] Student: {Model.Name}");
} else {
GD.Print("生成的名字是: " + name_test.GenerateName()); // Keep original log for reference
GD.Print("生成的名字是: " + nameTest.GenerateName()); // Keep original log for reference
}
}
@ -167,7 +167,7 @@ public partial class Student : CharacterBody2D
{
foreach (var p in path)
{
PathToGo.Enqueue(new Vector2I(p.X * 48 + 24, p.Y * 48 + 24));
_pathToGo.Enqueue(new Vector2I(p.X * 48 + 24, p.Y * 48 + 24));
}
}
@ -185,20 +185,20 @@ public partial class Student : CharacterBody2D
}
Vector2I vec = Vector2I.Zero;
while ((lab.GetMapNodeTypeOfPosition(vec) & Lab.MapNodeType.Walkable) == 0) {
vec.X = GD.RandRange(0, Lab.MAP_WIDTH);
vec.Y = GD.RandRange(0, Lab.MAP_HEIGHT);
vec.X = GD.RandRange(0, Lab.MapWidth);
vec.Y = GD.RandRange(0, Lab.MapHeight);
}
var pos = GlobalPosition;
if (State == CharacterState.Sitting) {
StateQueue.Enqueue(CharacterState.StandingUp);
StateQueue.Enqueue(CharacterState.Walking);
pos = lastWalkablePosition;
pos = _lastWalkablePosition;
} else if (State == CharacterState.Idle) {
State = CharacterState.Walking;
}
StateQueue.Enqueue(CharacterState.Idle);
MoveFollowPath(lab.GetShortestPath(lab.Point2Coord(pos), vec));
randomChangeBody();
RandomChangeBody();
}
public void GoToSeat() {
@ -216,23 +216,23 @@ public partial class Student : CharacterBody2D
if (i == 1) {
// Seat up
TargetDirection = Direction.Up;
targetSpecialPosition = new Vector2I(target.X * 48 + 24, target.Y * 48 + 12);
_targetSpecialPosition = new Vector2I(target.X * 48 + 24, target.Y * 48 + 12);
} else {
TargetDirection = Direction.Down;
targetSpecialPosition = new Vector2I(target.X * 48 + 24, target.Y * 48 + 18);
_targetSpecialPosition = new Vector2I(target.X * 48 + 24, target.Y * 48 + 18);
}
var pos = GlobalPosition;
if (State == CharacterState.Sitting) {
StateQueue.Enqueue(CharacterState.StandingUp);
StateQueue.Enqueue(CharacterState.Walking);
pos = lastWalkablePosition;
pos = _lastWalkablePosition;
} else if (State == CharacterState.Idle) {
State = CharacterState.Walking;
}
StateQueue.Enqueue(CharacterState.SittingDown);
StateQueue.Enqueue(CharacterState.Sitting);
var path = lab.GetShortestPath(lab.Point2Coord(pos), target);
lastWalkablePosition = new Vector2I(path.Last().X * 48 + 24, path.Last().Y * 48 + 24);
_lastWalkablePosition = new Vector2I(path.Last().X * 48 + 24, path.Last().Y * 48 + 24);
// if (lastWalkablePosition.X < targetSpecialPosition.X) {
// TargetDirection = Direction.Right;
// } else if (lastWalkablePosition.X > targetSpecialPosition.X) {
@ -245,16 +245,16 @@ public partial class Student : CharacterBody2D
// }
// }
MoveFollowPath(path);
randomChangeBody();
RandomChangeBody();
}
private void randomChangeBody()
private void RandomChangeBody()
{
GetNode<Sprite2D>("parts/body").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.BODY, Use16x16Sprites));
GetNode<Sprite2D>("parts/hairstyle").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.HAIR, Use16x16Sprites));
GetNode<Sprite2D>("parts/outfit").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.OUTFIT, Use16x16Sprites));
GetNode<Sprite2D>("parts/eye").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.EYE, Use16x16Sprites));
GetNode<Sprite2D>("parts/accessory").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.ACCESSORY, Use16x16Sprites));
GetNode<Sprite2D>("parts/smartphone").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.PHONE, Use16x16Sprites));
GetNode<Sprite2D>("parts/body").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Body, Use16X16Sprites));
GetNode<Sprite2D>("parts/hairstyle").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Hair, Use16X16Sprites));
GetNode<Sprite2D>("parts/outfit").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Outfit, Use16X16Sprites));
GetNode<Sprite2D>("parts/eye").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Eye, Use16X16Sprites));
GetNode<Sprite2D>("parts/accessory").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Accessory, Use16X16Sprites));
GetNode<Sprite2D>("parts/smartphone").Texture = ResourceLoader.Load<Texture2D>(Res.GetRandom(Res.Type.Phone, Use16X16Sprites));
}
}

View File

@ -7,14 +7,14 @@ public partial class TestMap : TileMapLayer
/// <summary>
/// The last cell that was highlighted. Used to avoid unnecessary updates.
/// </summary>
private Vector2I lastHighlightCell;
private readonly Vector2I highlightTileCoord = new(0, 5);
private readonly Vector2I vector2INegOne = new(-1, -1);
private Vector2I _lastHighlightCell;
private readonly Vector2I _highlightTileCoord = new(0, 5);
private readonly Vector2I _vector2INegOne = new(-1, -1);
// Called when the node enters the scene tree for the first time.
public override void _Ready()
{
// Initialize the lastHighlightCell to an invalid value.
lastHighlightCell = vector2INegOne;
_lastHighlightCell = _vector2INegOne;
}
/// <summary>
@ -26,14 +26,14 @@ public partial class TestMap : TileMapLayer
Vector2 mousePos = GetLocalMousePosition();
Vector2I cell = LocalToMap(mousePos);
if (cell != lastHighlightCell)
if (cell != _lastHighlightCell)
{
if (lastHighlightCell != vector2INegOne)
if (_lastHighlightCell != _vector2INegOne)
{
EraseCell(lastHighlightCell);
EraseCell(_lastHighlightCell);
}
lastHighlightCell = cell;
SetCell(cell, 0, highlightTileCoord);
_lastHighlightCell = cell;
SetCell(cell, 0, _highlightTileCoord);
}
}

View File

@ -8,40 +8,40 @@ public partial class TileMapping : Node
/// <summary>
/// From tile coordinates to pixel coordinates. If null, use the offset instead.
/// </summary>
private Dictionary<Vector2I, Vector2I> pixelMap;
private Dictionary<Vector2I, Vector2I> _pixelMap;
/// <summary>
/// If pixelMap is null, use this offset to convert tile coordinates to pixel coordinates.
/// </summary>
private Vector2I pixelOffset;
private Rect2I tileRect;
private Vector2I _pixelOffset;
private Rect2I _tileRect;
public TileMapping(Dictionary<Vector2I, Vector2I> map) {
pixelMap = map;
pixelOffset = new Vector2I(-int.MaxValue, -int.MaxValue);
_pixelMap = map;
_pixelOffset = new Vector2I(-int.MaxValue, -int.MaxValue);
}
public TileMapping(Vector2I offset, Rect2I rect) {
pixelMap = null;
pixelOffset = offset;
tileRect = rect;
_pixelMap = null;
_pixelOffset = offset;
_tileRect = rect;
}
public TileMapping() {}
public void Apply(TileMapLayer layer) {
// if pixelMap is not null, use all the pairs in pixelMap to set the tiles.
if (pixelMap != null) {
var sourceId = layer.GetCellSourceId(pixelMap.Keys.First());
foreach (var pair in pixelMap) {
if (_pixelMap != null) {
var sourceId = layer.GetCellSourceId(_pixelMap.Keys.First());
foreach (var pair in _pixelMap) {
layer.SetCell(pair.Key, sourceId, pair.Value);
}
} else {
var sourceId = layer.GetCellSourceId(tileRect.Position);
GD.Print(tileRect);
for (int x = tileRect.Position.X; x < tileRect.End.X; x++) {
for (int y = tileRect.Position.Y; y < tileRect.End.Y; y++) {
var sourceId = layer.GetCellSourceId(_tileRect.Position);
GD.Print(_tileRect);
for (int x = _tileRect.Position.X; x < _tileRect.End.X; x++) {
for (int y = _tileRect.Position.Y; y < _tileRect.End.Y; y++) {
var pos = new Vector2I(x, y);
layer.SetCell(pos, sourceId, pos + pixelOffset);
layer.SetCell(pos, sourceId, pos + _pixelOffset);
}
}
}