Merge branch 'feature/bugfixes_polish_II' into feature/build_0_7
# Conflicts: # scenes/scene_farm_outside_2d.tscn
This commit is contained in:
@@ -7,4 +7,17 @@ namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
/// </summary>
|
||||
public partial class DetectableInteractionArea : Area2D
|
||||
{
|
||||
[Export] public InteractionArea2D interactionArea2D;
|
||||
|
||||
public void InteractionAreaSelectionChanged(Variant instanceID)
|
||||
{
|
||||
if (instanceID.AsString() == GetInstanceId().ToString())
|
||||
{
|
||||
interactionArea2D.HighlightInteractable();
|
||||
}
|
||||
else
|
||||
{
|
||||
interactionArea2D.ResetHighlight();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,8 @@ namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
/// </summary>
|
||||
public partial class DetectionCross : Node2D
|
||||
{
|
||||
[Export] private Detector _detector;
|
||||
[Export] private Detector _collider;
|
||||
[Export] private ShapeCast2D _shapeCast2D;
|
||||
[Export] private float _xOffset;
|
||||
[Export] private float _yOffset;
|
||||
|
||||
@@ -17,6 +18,8 @@ public partial class DetectionCross : Node2D
|
||||
/// <param name="direction"></param>
|
||||
public void SetDirection(Vector2 direction)
|
||||
{
|
||||
_detector.Position = new Vector2(direction.X * _xOffset, direction.Y * _yOffset);
|
||||
Vector2 newPos = new Vector2(direction.X * _xOffset, direction.Y * _yOffset);
|
||||
_collider.Position = newPos;
|
||||
_shapeCast2D.TargetPosition = newPos;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Babushka.scripts.CSharp.Common.Services;
|
||||
using Babushka.scripts.CSharp.Low_Code.Variables;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
@@ -8,18 +10,11 @@ namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
/// </summary>
|
||||
public partial class Detector : Area2D
|
||||
{
|
||||
|
||||
[Export] private bool _active = true;
|
||||
[Export] private ShapeCast2D _shapeCast2D;
|
||||
[Export] private VariableResource _itemToTriggerResource;
|
||||
|
||||
/// <summary>
|
||||
/// Called when entering an interactionArea node.
|
||||
/// </summary>
|
||||
[Signal] public delegate void InteractableEnteredEventHandler();
|
||||
|
||||
/// <summary>
|
||||
/// Called when exiting an interactionArea node.
|
||||
/// </summary>
|
||||
[Signal] public delegate void InteractableExitedEventHandler();
|
||||
private List<ulong> _areasInDetector = new();
|
||||
|
||||
public bool IsActive
|
||||
{
|
||||
@@ -41,29 +36,62 @@ public partial class Detector : Area2D
|
||||
/// Called every time this node enters an Area2D.
|
||||
/// </summary>
|
||||
/// <param name="area"></param>
|
||||
public void OnEnteredInteractable(Node area)
|
||||
public void OnEnteredInteractable(Area2D area)
|
||||
{
|
||||
if (!_active || !InputService.Instance.InputEnabled)
|
||||
return;
|
||||
|
||||
if (area is DetectableInteractionArea interactionArea2D)
|
||||
{
|
||||
EmitSignal(SignalName.InteractableEntered);
|
||||
}
|
||||
PopulateList();
|
||||
CalculateClosestInteractable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called whenever this node exits an Area2D.
|
||||
/// </summary>
|
||||
/// <param name="area"></param>
|
||||
public void OnExitedInteractable(Node area)
|
||||
public void OnExitedInteractable(Area2D area)
|
||||
{
|
||||
if (!_active || !InputService.Instance.InputEnabled)
|
||||
return;
|
||||
|
||||
if (area is DetectableInteractionArea interactionArea2D)
|
||||
PopulateList();
|
||||
CalculateClosestInteractable();
|
||||
}
|
||||
|
||||
private void PopulateList()
|
||||
{
|
||||
// repopulate the list of areas in the detector to account for enabled / disabled areas
|
||||
var currentOverlap = GetOverlappingAreas();
|
||||
_areasInDetector = new List<ulong>();
|
||||
|
||||
foreach (var area2D in currentOverlap)
|
||||
{
|
||||
EmitSignal(SignalName.InteractableExited);
|
||||
if (area2D is DetectableInteractionArea detectable)
|
||||
{
|
||||
ulong id = detectable.GetInstanceId();
|
||||
_areasInDetector.Add(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateClosestInteractable()
|
||||
{
|
||||
float smallestDistance = float.MaxValue;
|
||||
string closestInteractable = null;
|
||||
foreach (var area in _areasInDetector)
|
||||
{
|
||||
Area2D? area2D = InstanceFromId(area) as Area2D;
|
||||
if(area2D == null)
|
||||
continue;
|
||||
|
||||
float distance = area2D.GlobalPosition.DistanceSquaredTo(ToGlobal(_shapeCast2D.TargetPosition));
|
||||
if (distance < smallestDistance)
|
||||
{
|
||||
closestInteractable = area.ToString();
|
||||
smallestDistance = distance;
|
||||
}
|
||||
}
|
||||
_itemToTriggerResource.Payload = closestInteractable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
using System.Linq;
|
||||
using Babushka.scripts.CSharp.Common.Services;
|
||||
using Babushka.scripts.CSharp.Low_Code.Variables;
|
||||
using Godot;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
|
||||
public partial class InteractionArea2D : Node2D
|
||||
{
|
||||
[ExportGroup("Settings")]
|
||||
[ExportGroup("Settings")]
|
||||
[Export] private VariableListener _selectionChangeListener;
|
||||
[Export] private Area2D _area;
|
||||
[Export] private Label _label;
|
||||
[Export] private bool _active = true;
|
||||
@@ -25,9 +27,17 @@ public partial class InteractionArea2D : Node2D
|
||||
public bool IsActive
|
||||
{
|
||||
get => _active;
|
||||
set => _active = value;
|
||||
set
|
||||
{
|
||||
ProcessMode = value ? ProcessModeEnum.Inherit : ProcessModeEnum.Disabled;
|
||||
Visible = value;
|
||||
_selectionChangeListener.ProcessMode = value ? ProcessModeEnum.Inherit : ProcessModeEnum.Disabled;
|
||||
_active = value;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSelectedByDetector { get; set; } = false;
|
||||
|
||||
public void SetActiveInverse(bool active)
|
||||
{
|
||||
IsActive = !active;
|
||||
@@ -41,8 +51,10 @@ public partial class InteractionArea2D : Node2D
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPlayerEntered(Node2D player)
|
||||
public void HighlightInteractable()
|
||||
{
|
||||
IsSelectedByDetector = true;
|
||||
|
||||
if (!_active || !InputService.Instance.InputEnabled)
|
||||
return;
|
||||
|
||||
@@ -51,15 +63,16 @@ public partial class InteractionArea2D : Node2D
|
||||
|
||||
if (!_useOutline)
|
||||
return;
|
||||
|
||||
|
||||
foreach (var sprite in _spritesToOutline)
|
||||
{
|
||||
sprite.Material = _outlineMaterial;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnPlayerExited(Node2D player)
|
||||
public void ResetHighlight()
|
||||
{
|
||||
IsSelectedByDetector = false;
|
||||
_label.Hide();
|
||||
|
||||
if (!_useOutline)
|
||||
@@ -76,6 +89,9 @@ public partial class InteractionArea2D : Node2D
|
||||
{
|
||||
if (!_active || !InputService.Instance.InputEnabled)
|
||||
return;
|
||||
|
||||
if(!IsSelectedByDetector)
|
||||
return;
|
||||
|
||||
if (@event.IsAction("interact") && @event.IsPressed())
|
||||
{
|
||||
@@ -92,16 +108,7 @@ public partial class InteractionArea2D : Node2D
|
||||
{
|
||||
if (_area.HasOverlappingAreas())
|
||||
{
|
||||
_label.Hide();
|
||||
|
||||
if (_useOutline)
|
||||
{
|
||||
for (var i = 0; i < _spritesToOutline.Length; i++)
|
||||
{
|
||||
var sprite = _spritesToOutline[i];
|
||||
sprite.Material = _backupMaterials[i];
|
||||
}
|
||||
}
|
||||
ResetHighlight();
|
||||
Interact();
|
||||
}
|
||||
}
|
||||
@@ -124,4 +131,5 @@ public partial class InteractionArea2D : Node2D
|
||||
_label.Hide();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,12 +1,14 @@
|
||||
using Babushka.scripts.CSharp.Common.CharacterControls;
|
||||
using Babushka.scripts.CSharp.Common.Savegame;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Babushka.scripts.CSharp.Common.Farming;
|
||||
|
||||
/// <summary>
|
||||
/// Enables a preset field in the scene sothat it can be used for farming.
|
||||
/// </summary>
|
||||
public partial class FieldActivator : Node
|
||||
public partial class FieldActivator : Node, ISaveable
|
||||
{
|
||||
[Export] private FieldBehaviour2D _field;
|
||||
[Export] private InteractionArea2D _activatorArea;
|
||||
@@ -18,6 +20,7 @@ public partial class FieldActivator : Node
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
LoadFromSaveData();
|
||||
ToggleInteractionArea();
|
||||
}
|
||||
|
||||
@@ -32,6 +35,8 @@ public partial class FieldActivator : Node
|
||||
_field.UpdateFieldState(FieldState.Tilled);
|
||||
EmitSignal(SignalName.FieldCreated, _field);
|
||||
_used = true;
|
||||
ToggleInteractionArea();
|
||||
UpdateSaveData();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,6 +47,8 @@ public partial class FieldActivator : Node
|
||||
/// <param name="activated"></param>
|
||||
public void RakeActivated(bool activated)
|
||||
{
|
||||
if (_used || ProcessMode == ProcessModeEnum.Disabled)
|
||||
return;
|
||||
_rakeInHand = activated;
|
||||
ToggleInteractionArea();
|
||||
}
|
||||
@@ -50,5 +57,29 @@ public partial class FieldActivator : Node
|
||||
{
|
||||
_activatorArea.IsActive = !_used && _rakeInHand;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateSaveData()
|
||||
{
|
||||
var payloadData = new Dictionary<string, Variant>
|
||||
{
|
||||
{ "field_activator_used", _used }
|
||||
};
|
||||
|
||||
string id = GetMeta("SaveID").AsString();
|
||||
SavegameService.AppendDataToSave( id, payloadData);
|
||||
}
|
||||
|
||||
public void LoadFromSaveData()
|
||||
{
|
||||
string id = GetMeta("SaveID").AsString();
|
||||
|
||||
Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
|
||||
if (save.Count > 0)
|
||||
{
|
||||
if (save.TryGetValue("field_activator_used", out Variant usedVar))
|
||||
{
|
||||
_used = usedVar.AsBool();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,6 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
|
||||
[ExportGroup("Field Interactions")]
|
||||
[Export] public InteractionArea2D PlantingInteraction;
|
||||
[Export] public InteractionArea2D FieldInteractionArea;
|
||||
|
||||
[ExportGroup("Configuration")]
|
||||
[Export] public Node2D PlantingPlaceholder;
|
||||
@@ -48,6 +47,8 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
private bool _canWater;
|
||||
private int _currentDay;
|
||||
|
||||
public bool IsPlanted;
|
||||
|
||||
private PlantBehaviour2D? _currentPlant;
|
||||
|
||||
private const string DAY_COUNTER_SAVE_ID = "12c6da2e-fc71-4281-a04a-dfd3c7943975";
|
||||
@@ -59,9 +60,9 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
// fieldstate == tilled / watered && samen im Inventar
|
||||
_canPlant = (FieldState == FieldState.Tilled || FieldState == FieldState.Watered) && _seedsActive;
|
||||
// fieldstate == tilled && watering can ausgewählt
|
||||
_canWater = (FieldState == FieldState.Tilled || FieldState == FieldState.Planted) && _wateringCanActive;
|
||||
_canWater = (FieldState == FieldState.Tilled || IsPlanted) && _wateringCanActive && WateringCanState.GetFillState() > 0;
|
||||
|
||||
FieldInteractionArea.IsActive = _canPlant || _canWater;
|
||||
PlantingInteraction.IsActive = _canPlant || _canWater;
|
||||
}
|
||||
|
||||
public void ActivatedSeedInInventory(bool activated)
|
||||
@@ -104,17 +105,14 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
case FieldState.Tilled:
|
||||
FieldState = FieldState.Tilled;
|
||||
_fieldSprite.Texture = Tilled;
|
||||
PlantingInteraction.IsActive = true;
|
||||
if(!IsPlanted)
|
||||
PlantingInteraction.IsActive = true;
|
||||
break;
|
||||
case FieldState.Watered:
|
||||
FieldState = FieldState.Watered;
|
||||
_fieldSprite.Texture = Watered;
|
||||
PlantingInteraction.IsActive = true;
|
||||
break;
|
||||
case FieldState.Planted:
|
||||
FieldState = FieldState.Planted;
|
||||
_fieldSprite.Texture = Tilled;
|
||||
PlantingInteraction.IsActive = false;
|
||||
if(!IsPlanted)
|
||||
PlantingInteraction.IsActive = true;
|
||||
break;
|
||||
default:
|
||||
FieldState = FieldState.NotFound;
|
||||
@@ -125,7 +123,6 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
UpdateSaveData();
|
||||
}
|
||||
|
||||
|
||||
public void Water()
|
||||
{
|
||||
if (WateringCanState.GetFillState() > 0 && FieldState != FieldState.Watered)
|
||||
@@ -151,7 +148,7 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
if (_canPlant && TryPlant())
|
||||
{
|
||||
EmitSignal(SignalName.Planted);
|
||||
UpdateFieldState(FieldState.Planted);
|
||||
UpdateSaveData();
|
||||
}
|
||||
|
||||
if (_canWater)
|
||||
@@ -159,6 +156,16 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
Water();
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangePlantedState()
|
||||
{
|
||||
IsPlanted = true;
|
||||
if(FieldState == FieldState.Tilled)
|
||||
_fieldSprite.Texture = Tilled;
|
||||
if(FieldState == FieldState.Watered)
|
||||
_fieldSprite.Texture = Watered;
|
||||
PlantingInteraction.IsActive = false;
|
||||
}
|
||||
|
||||
private bool TryPlant()
|
||||
{
|
||||
@@ -187,6 +194,7 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
|
||||
if (_currentPlant != null)
|
||||
{
|
||||
ChangePlantedState();
|
||||
_currentPlant.DayPlanted = _currentDay;
|
||||
}
|
||||
}
|
||||
@@ -209,6 +217,7 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
{
|
||||
_currentPlant = null;
|
||||
UpdateFieldState(FieldState.Empty, true);
|
||||
IsPlanted = false;
|
||||
}
|
||||
|
||||
#region SAVE AND LOAD
|
||||
@@ -221,10 +230,10 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
var payloadData = new Dictionary<string, Variant>
|
||||
{
|
||||
{ "field_state", (int)FieldState },
|
||||
{ "day_count_on_last_exit", _currentDay}
|
||||
{ "day_count_on_last_exit", _currentDay},
|
||||
};
|
||||
|
||||
if (_currentPlant != null)
|
||||
if (IsPlanted)
|
||||
{
|
||||
payloadData.Add(
|
||||
"plant_data", new Dictionary<string, Variant>()
|
||||
@@ -258,6 +267,7 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
// get plant first because it's also relevant for the field state
|
||||
if (save.TryGetValue("plant_data", out Variant plantDataVar))
|
||||
{
|
||||
IsPlanted = true;
|
||||
Dictionary<string, Variant> plantDataDict = plantDataVar.AsGodotDictionary<string, Variant>();
|
||||
|
||||
if (plantDataDict.TryGetValue("prefab_path", out Variant prefabPathVar))
|
||||
@@ -314,17 +324,10 @@ public partial class FieldBehaviour2D : Sprite2D, ISaveable
|
||||
// if day is today, then just use the provided field state as is.
|
||||
if (CalendarController.Instance != null && _currentDay != lastDayCount)
|
||||
{
|
||||
// if the field was watered the day before, set it to tilled or planted.
|
||||
// if the field was watered the day before, set it to tilled
|
||||
if (fieldStateInt == 3)
|
||||
{
|
||||
if (_currentPlant != null)
|
||||
{
|
||||
fieldStateInt = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
fieldStateInt = 1;
|
||||
}
|
||||
fieldStateInt = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ public enum FieldState
|
||||
{
|
||||
Empty = 0,
|
||||
Tilled = 1,
|
||||
Planted = 2,
|
||||
Watered = 3,
|
||||
NotFound = 99
|
||||
}
|
||||
@@ -7,11 +7,16 @@ public partial class WellBehaviour : Node2D
|
||||
{
|
||||
[Export] private InteractionArea2D _interactionArea;
|
||||
|
||||
public override void _Ready()
|
||||
public override void _EnterTree()
|
||||
{
|
||||
WateringCanState.WateringCanActiveStateChanged += OnWateringCanStateChanged;
|
||||
}
|
||||
|
||||
public override void _ExitTree()
|
||||
{
|
||||
WateringCanState.WateringCanActiveStateChanged -= OnWateringCanStateChanged;
|
||||
}
|
||||
|
||||
private void OnWateringCanStateChanged(bool state)
|
||||
{
|
||||
_interactionArea.IsActive = state;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
using Godot;
|
||||
using Babushka.scripts.CSharp.Common.Savegame;
|
||||
using Godot.Collections;
|
||||
|
||||
/// <summary>
|
||||
/// Simple collectible scene objects with saveable state.
|
||||
/// </summary>
|
||||
public partial class TrashObject : Sprite2D, ISaveable
|
||||
{
|
||||
private bool _collected;
|
||||
|
||||
/// <summary>
|
||||
/// Loads objects state on scene start.
|
||||
/// </summary>
|
||||
public override void _Ready()
|
||||
{
|
||||
LoadFromSaveData();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets object state to collected and updates save data.
|
||||
/// </summary>
|
||||
public void Collect()
|
||||
{
|
||||
SetCollectedState();
|
||||
UpdateSaveData();
|
||||
}
|
||||
|
||||
private void SetCollectedState()
|
||||
{
|
||||
_collected = true;
|
||||
Visible = false;
|
||||
ProcessMode = ProcessModeEnum.Disabled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the save data with the current state of the object.
|
||||
/// </summary>
|
||||
public void UpdateSaveData()
|
||||
{
|
||||
var payloadData = new Dictionary<string, Variant>
|
||||
{
|
||||
{ "collectedState", _collected },
|
||||
};
|
||||
|
||||
string id = GetMeta("SaveID").AsString();
|
||||
SavegameService.AppendDataToSave( id, payloadData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads objects state from save data.
|
||||
/// </summary>
|
||||
public void LoadFromSaveData()
|
||||
{
|
||||
string id = GetMeta("SaveID").AsString();
|
||||
|
||||
Dictionary<string, Variant> save = SavegameService.GetSaveData(id);
|
||||
if (save.Count > 0)
|
||||
{
|
||||
if (save.TryGetValue("collectedState", out Variant collectedVar))
|
||||
{
|
||||
if (collectedVar.AsBool())
|
||||
{
|
||||
SetCollectedState();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c2cgj153m05sp
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Threading.Tasks;
|
||||
using Babushka.scripts.CSharp.Common.Savegame;
|
||||
using Babushka.scripts.CSharp.Low_Code.Variables;
|
||||
using Godot;
|
||||
using Godot.Collections;
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ public partial class VariableListener : Node
|
||||
/// </summary>
|
||||
public void EventPayloadChanged(Variant payload, Variant oldPayload)
|
||||
{
|
||||
if (ProcessMode == ProcessModeEnum.Disabled)
|
||||
return;
|
||||
|
||||
if(_showLog)
|
||||
GD.Print($"Calling Event Payload Changed Signals on: " + Name);
|
||||
EmitSignal(SignalName.PayloadChanged, payload, oldPayload);
|
||||
|
||||
Reference in New Issue
Block a user