Files
AppleHillsProduction/Assets/Scripts/DamianExperiments/LawnMowerPuzzle/LawnMowerChaseBehaviour.cs
tschesky 011901eb8f Refactoring of the interaction system and preliminary integration of save/load functionality across the game. (#44)
### Interactables Architecture Refactor
- Converted composition to inheritance, moved from component-based to class-based interactables. No more requirement for chain of "Interactable -> Item" etc.
- Created `InteractableBase` abstract base class with common functionality that replaces the old component
- Specialized child classes: `Pickup`, `ItemSlot`, `LevelSwitch`, `MinigameSwitch`, `CombinationItem`, `OneClickInteraction` are now children classes
- Light updates to the interactable inspector, moved some things arround, added collapsible inspector sections in the  UI for better editor experience

### State Machine Integration
- Custom `AppleMachine` inheritong from Pixelplacement's StateMachine which implements our own interface for saving, easy place for future improvements
- Replaced all previous StateMachines by `AppleMachine`
- Custom `AppleState`  extends from default `State`. Added serialization, split state logic into "EnterState", "RestoreState", "ExitState" allowing for separate logic when triggering in-game vs loading game
- Restores directly to target state without triggering transitional logic
- Migration tool converts existing instances

### Prefab Organization
- Saved changes from scenes into prefabs
- Cleaned up duplicated components, confusing prefabs hierarchies
- Created prefab variants where possible
- Consolidated Environment prefabs and moved them out of Placeholders subfolder into main Environment folder
- Organized item prefabs from PrefabsPLACEHOLDER into proper Items folder
- Updated prefab references - All scene references updated to new locations
- Removed placeholder files from Characters, Levels, UI, and Minigames folders

### Scene Updates
- Quarry scene with major updates
- Saved multiple working versions (Quarry, Quarry_Fixed, Quarry_OLD)
- Added proper lighting data
- Updated all interactable components to new architecture

### Minor editor tools
- New tool for testing cards from an editor window (no in-scene object required)
- Updated Interactable Inspector
- New debug option to opt in-and-out of the save/load system
- Tooling for easier migration

Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com>
Reviewed-on: #44
2025-11-03 10:12:51 +00:00

161 lines
4.6 KiB
C#

using Core.SaveLoad;
using UnityEngine;
using Pixelplacement;
public class LawnMowerChaseBehaviour : AppleState
{
public Spline ChaseSpline;
public Transform LawnMowerObject;
public float chaseDuration;
public float chaseDelay;
[Range(0, 1)] public float startPercentage; // Exposed in Inspector
private const float AnchorThreshold = 0.05f;
private bool _wasAtStart = false;
private bool _wasAtEnd = false;
// For initial tween tracking
private bool _initialTweenActive = true;
private float _initialTargetAnchor = 1f;
//Reference to the gardener's gameobject
public GameObject gardenerRef = null;
public Animator gardenerAnimator = null;
public bool gardenerChasing = true;
public GardenerAudioController gardenerAudioController;
public override void OnEnterState()
{
LawnMowerObject.position = ChaseSpline.GetPosition(startPercentage);
float distanceToStart = Mathf.Abs(startPercentage - 0f);
float distanceToEnd = Mathf.Abs(startPercentage - 1f);
gardenerAudioController.StartMowerSound();
if (distanceToStart < distanceToEnd)
{
// Tween from startPercentage to 1
_initialTargetAnchor = 1f;
Tween.Spline(
ChaseSpline,
LawnMowerObject,
startPercentage,
1,
false,
chaseDuration * (1 - startPercentage),
chaseDelay,
Tween.EaseInOut,
Tween.LoopType.None
);
}
else
{
// Tween from startPercentage to 0
_initialTargetAnchor = 0f;
Tween.Spline(
ChaseSpline,
LawnMowerObject,
startPercentage,
0,
false,
chaseDuration * startPercentage,
chaseDelay,
Tween.EaseInOut,
Tween.LoopType.None
);
}
_initialTweenActive = true;
}
public override void OnRestoreState(string data)
{
OnEnterState();
}
void Update()
{
float percentage = ChaseSpline.ClosestPoint(LawnMowerObject.position);
// Handle initial tween completion
if (_initialTweenActive)
{
if (Mathf.Abs(percentage - _initialTargetAnchor) <= AnchorThreshold)
{
// Start ping-pong tween between extremes
StartPingPongTween(_initialTargetAnchor, 1f - _initialTargetAnchor);
_initialTweenActive = false;
}
return; // Don't process flip logic until ping-pong starts
}
// Detect start anchor
if (percentage <= AnchorThreshold)
{
if (!_wasAtStart)
{
flipSprite();
_wasAtStart = true;
_wasAtEnd = false;
}
}
// Detect end anchor
else if (percentage >= 1f - AnchorThreshold)
{
if (!_wasAtEnd)
{
flipSprite();
_wasAtEnd = true;
_wasAtStart = false;
}
}
else
{
_wasAtStart = false;
_wasAtEnd = false;
}
}
private void StartPingPongTween(float from, float to)
{
Tween.Spline(
ChaseSpline,
LawnMowerObject,
from,
to,
false,
chaseDuration,
0,
Tween.EaseLinear,
Tween.LoopType.PingPong
);
}
private void flipSprite()
{
if (gardenerRef == null)
{
gardenerRef = GameObject.Find("GardenerRunningSprite");
gardenerAnimator = gardenerRef.GetComponent<Animator>();
}
Vector3 scale = LawnMowerObject.transform.localScale;
Vector3 rotation = LawnMowerObject.transform.eulerAngles;
scale.x *= -1;
rotation.z *= -1;
LawnMowerObject.transform.localScale = scale;
LawnMowerObject.transform.eulerAngles = rotation;
if (gardenerChasing == true)
{
gardenerRef.transform.localPosition = new Vector3 (-15, -9f, gardenerRef.transform.localPosition.z);
gardenerAnimator.SetBool("IsScared?", true);
gardenerChasing = false;
}
else
{
gardenerRef.transform.localPosition = new Vector3(21f, 16f, gardenerRef.transform.localPosition.z);
gardenerAnimator.SetBool("IsScared?", false);
gardenerChasing = true;
}
}
}