From 0c930d09a4adfd179b9ec7659694a0e0cc60d64c Mon Sep 17 00:00:00 2001 From: Michal Pikulski Date: Thu, 4 Sep 2025 00:00:46 +0200 Subject: [PATCH] [Player][Interactions] Pulver moves to item and goes back. Item disappears, but in wrong order --- Assets/Data/Settings.meta | 8 ++ Assets/Data/Settings/DefaultSettings.asset | 16 +++ .../Data/Settings/DefaultSettings.asset.meta | 8 ++ .../Prefabs/Characters/PulverCharacter.prefab | 2 +- Assets/Prefabs/Items/BasePickup.prefab | 2 +- Assets/Prefabs/Levels/BaseLevelSwitch.prefab | 2 +- Assets/Scenes/AppleHillsOverworld.unity | 129 +++++++++++++++++- Assets/Scripts/FollowerController.cs | 118 ++++++++++++---- Assets/Scripts/GameManager.cs | 36 +++++ Assets/Scripts/GameManager.cs.meta | 3 + Assets/Scripts/GameSettings.cs | 11 ++ Assets/Scripts/GameSettings.cs.meta | 3 + Assets/Scripts/LevelSwitch.cs | 7 +- Assets/Scripts/Pickup.cs | 73 +++++++++- Assets/Scripts/PlayerTouchController.cs | 51 +++++++ Assets/Scripts/SceneManagerService.cs | 26 +++- ProjectSettings/Physics2DSettings.asset | 2 +- ProjectSettings/TagManager.asset | 1 + 18 files changed, 455 insertions(+), 43 deletions(-) create mode 100644 Assets/Data/Settings.meta create mode 100644 Assets/Data/Settings/DefaultSettings.asset create mode 100644 Assets/Data/Settings/DefaultSettings.asset.meta create mode 100644 Assets/Scripts/GameManager.cs create mode 100644 Assets/Scripts/GameManager.cs.meta create mode 100644 Assets/Scripts/GameSettings.cs create mode 100644 Assets/Scripts/GameSettings.cs.meta diff --git a/Assets/Data/Settings.meta b/Assets/Data/Settings.meta new file mode 100644 index 00000000..a3c356fa --- /dev/null +++ b/Assets/Data/Settings.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fcd99d46037b3e44abe09d64d0fa2e47 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Data/Settings/DefaultSettings.asset b/Assets/Data/Settings/DefaultSettings.asset new file mode 100644 index 00000000..b6d26cb3 --- /dev/null +++ b/Assets/Data/Settings/DefaultSettings.asset @@ -0,0 +1,16 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!114 &11400000 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e4ec438b455a4044957501c2c66a6f4b, type: 3} + m_Name: DefaultSettings + m_EditorClassIdentifier: + playerStopDistance: 10 + followerPickupDelay: 0.2 diff --git a/Assets/Data/Settings/DefaultSettings.asset.meta b/Assets/Data/Settings/DefaultSettings.asset.meta new file mode 100644 index 00000000..2427ae17 --- /dev/null +++ b/Assets/Data/Settings/DefaultSettings.asset.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 924922151a72ae8439be5090a3feaef9 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 11400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Prefabs/Characters/PulverCharacter.prefab b/Assets/Prefabs/Characters/PulverCharacter.prefab index 4b73ac09..a2922499 100644 --- a/Assets/Prefabs/Characters/PulverCharacter.prefab +++ b/Assets/Prefabs/Characters/PulverCharacter.prefab @@ -13,7 +13,7 @@ GameObject: - component: {fileID: 3435632802124758411} m_Layer: 8 m_Name: PulverCharacter - m_TagString: Untagged + m_TagString: Pulver m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 diff --git a/Assets/Prefabs/Items/BasePickup.prefab b/Assets/Prefabs/Items/BasePickup.prefab index 2809c72a..758e5a3f 100644 --- a/Assets/Prefabs/Items/BasePickup.prefab +++ b/Assets/Prefabs/Items/BasePickup.prefab @@ -13,7 +13,7 @@ GameObject: - component: {fileID: 3070149615425714466} - component: {fileID: 7616859841301711022} - component: {fileID: 592045584872845087} - m_Layer: 6 + m_Layer: 0 m_Name: BasePickup m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/Prefabs/Levels/BaseLevelSwitch.prefab b/Assets/Prefabs/Levels/BaseLevelSwitch.prefab index d5291c3c..dde07a35 100644 --- a/Assets/Prefabs/Levels/BaseLevelSwitch.prefab +++ b/Assets/Prefabs/Levels/BaseLevelSwitch.prefab @@ -13,7 +13,7 @@ GameObject: - component: {fileID: 841695541655102207} - component: {fileID: 4981092805118965486} - component: {fileID: 1397300447834037203} - m_Layer: 6 + m_Layer: 0 m_Name: BaseLevelSwitch m_TagString: Untagged m_Icon: {fileID: 0} diff --git a/Assets/Scenes/AppleHillsOverworld.unity b/Assets/Scenes/AppleHillsOverworld.unity index a671c813..105ba5bf 100644 --- a/Assets/Scenes/AppleHillsOverworld.unity +++ b/Assets/Scenes/AppleHillsOverworld.unity @@ -488,6 +488,81 @@ PrefabInstance: m_AddedGameObjects: [] m_AddedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: b5fc01af35233eb4cbeede05e50a7c34, type: 3} +--- !u!1 &416453392 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3} + m_PrefabInstance: {fileID: 1950557796102186365} + m_PrefabAsset: {fileID: 0} +--- !u!114 &416453396 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 416453392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f6eb1402c17e84a9282a7f0f62eb584f, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 5 + radius: 2 + height: 2 + canMove: 1 + maxSpeed: 15 + gravity: {x: NaN, y: NaN, z: NaN} + groundMask: + serializedVersion: 2 + m_Bits: 4294967295 + centerOffsetCompatibility: NaN + repathRateCompatibility: NaN + canSearchCompability: 0 + orientation: 1 + enableRotation: 0 + autoRepath: + mode: 2 + interval: 0.5 + sensitivity: 10 + maximumInterval: 2 + visualizeSensitivity: 0 + targetCompatibility: {fileID: 0} + maxAcceleration: -2.5 + rotationSpeed: 360 + slowdownDistance: 3 + pickNextWaypointDist: 2 + endReachedDistance: 0.5 + alwaysDrawGizmos: 0 + slowWhenNotFacingTarget: 1 + whenCloseToDestination: 0 + constrainInsideGraph: 0 +--- !u!114 &416453397 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 416453392} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 373b52eb9bf8c40f785bb6947a1aee66, type: 3} + m_Name: + m_EditorClassIdentifier: + version: 1 + drawGizmos: 1 + detailedGizmos: 0 + startEndModifier: + addPoints: 0 + exactStartPoint: 3 + exactEndPoint: 3 + useRaycasting: 0 + mask: + serializedVersion: 2 + m_Bits: 4294967295 + useGraphRaycasting: 0 + traversableTags: -1 + tagPenalties: 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + graphMask: + value: -1 --- !u!1001 &448642088 PrefabInstance: m_ObjectHideFlags: 0 @@ -633,6 +708,7 @@ Transform: - {fileID: 954512636} - {fileID: 535638824} - {fileID: 189988800} + - {fileID: 2027860879} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} --- !u!4 &754397347 stripped @@ -22942,6 +23018,51 @@ Tilemap: e31: 0 e32: 0 e33: 1 +--- !u!1 &2027860878 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2027860879} + - component: {fileID: 2027860880} + m_Layer: 0 + m_Name: GameManager + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2027860879 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2027860878} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 638340961} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2027860880 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2027860878} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: b9333cd9ca0e44769ef1913d10231047, type: 3} + m_Name: + m_EditorClassIdentifier: + gameSettings: {fileID: 11400000, guid: 924922151a72ae8439be5090a3feaef9, type: 2} --- !u!4 &2102167558 stripped Transform: m_CorrespondingSourceObject: {fileID: 2844046668579196942, guid: b5fc01af35233eb4cbeede05e50a7c34, type: 3} @@ -23002,7 +23123,13 @@ PrefabInstance: m_RemovedComponents: [] m_RemovedGameObjects: [] m_AddedGameObjects: [] - m_AddedComponents: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3} + insertIndex: -1 + addedObject: {fileID: 416453397} + - targetCorrespondingSourceObject: {fileID: 1102400833121127473, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3} + insertIndex: -1 + addedObject: {fileID: 416453396} m_SourcePrefab: {fileID: 100100000, guid: 8ac0210dbf9d7754e9526d6d5c214f49, type: 3} --- !u!1001 &8865498003578620591 PrefabInstance: diff --git a/Assets/Scripts/FollowerController.cs b/Assets/Scripts/FollowerController.cs index 3278d7f5..9f43182c 100644 --- a/Assets/Scripts/FollowerController.cs +++ b/Assets/Scripts/FollowerController.cs @@ -27,6 +27,9 @@ public class FollowerController : MonoBehaviour public float thresholdNear = 0.5f; public float stopThreshold = 0.1f; // Stop moving when within this distance private float playerMaxSpeed = 5f; + private const float followerSpeedMultiplier = 1.2f; + private float followerMaxSpeed = 6f; // Default, will be set from player + private float defaultFollowerMaxSpeed = 6f; // Default fallback value private Animator animator; private Transform artTransform; @@ -72,6 +75,8 @@ public class FollowerController : MonoBehaviour if (playerAIPath != null) { playerMaxSpeed = playerAIPath.maxSpeed; + defaultFollowerMaxSpeed = playerMaxSpeed; + followerMaxSpeed = playerMaxSpeed * followerSpeedMultiplier; } } else @@ -95,27 +100,29 @@ public class FollowerController : MonoBehaviour if (playerTransform == null) return; // Still missing, skip update } - // Determine direction: use player's velocity if available, else lastMoveDir - Vector3 playerPos = playerTransform.position; - Vector3 moveDir = Vector3.zero; - if (playerAIPath != null && playerAIPath.velocity.magnitude > 0.01f) + if (isManualFollowing) { - moveDir = playerAIPath.velocity.normalized; - lastMoveDir = moveDir; // Update last valid direction - } - else - { - moveDir = lastMoveDir; // Use last direction if stationary - } - // Calculate target point behind player - targetPoint = playerPos - moveDir * followDistance; - targetPoint.z = 0; // For 2D + // Determine direction: use player's velocity if available, else lastMoveDir + Vector3 playerPos = playerTransform.position; + Vector3 moveDir = Vector3.zero; + if (playerAIPath != null && playerAIPath.velocity.magnitude > 0.01f) + { + moveDir = playerAIPath.velocity.normalized; + lastMoveDir = moveDir; // Update last valid direction + } + else + { + moveDir = lastMoveDir; // Use last direction if stationary + } + // Calculate target point behind player + targetPoint = playerPos - moveDir * followDistance; + targetPoint.z = 0; // For 2D - // Always use manual following unless GoToPoint is called - isManualFollowing = true; - if (aiPath != null) - { - aiPath.enabled = false; + // Only disable aiPath if in manual mode + if (aiPath != null) + { + aiPath.enabled = false; + } } } @@ -139,14 +146,17 @@ public class FollowerController : MonoBehaviour // Manual movement logic with acceleration/deceleration and stop threshold if (isManualFollowing) { - float dist = Vector3.Distance(transform.position, targetPoint); + // 2D distance calculation (ignore z) + Vector2 current2D = new Vector2(transform.position.x, transform.position.y); + Vector2 target2D = new Vector2(targetPoint.x, targetPoint.y); + float dist = Vector2.Distance(current2D, target2D); if (dist > stopThreshold) { - float desiredSpeed = playerMaxSpeed; + float desiredSpeed = followerMaxSpeed; if (dist > thresholdFar) { - // Accelerate to player's max speed - desiredSpeed = Mathf.Min(currentSpeed + acceleration * Time.deltaTime, playerMaxSpeed); + // Accelerate to follower's max speed + desiredSpeed = Mathf.Min(currentSpeed + acceleration * Time.deltaTime, followerMaxSpeed); } else if (dist <= thresholdNear && dist > stopThreshold) { @@ -155,8 +165,8 @@ public class FollowerController : MonoBehaviour } else { - // Maintain player's max speed - desiredSpeed = playerMaxSpeed; + // Maintain follower's max speed + desiredSpeed = followerMaxSpeed; } currentSpeed = desiredSpeed; Vector3 dir = (targetPoint - transform.position).normalized; @@ -176,12 +186,12 @@ public class FollowerController : MonoBehaviour if (isManualFollowing) { // Use currentSpeed for manual following - normalizedSpeed = currentSpeed / playerMaxSpeed; + normalizedSpeed = currentSpeed / followerMaxSpeed; } else if (aiPath != null) { // Use aiPath velocity for pathfinding mode - normalizedSpeed = aiPath.velocity.magnitude / playerMaxSpeed; + normalizedSpeed = aiPath.velocity.magnitude / followerMaxSpeed; } animator.SetFloat("Speed", Mathf.Clamp01(normalizedSpeed)); } @@ -194,10 +204,64 @@ public class FollowerController : MonoBehaviour if (aiPath != null) { aiPath.enabled = true; + aiPath.maxSpeed = followerMaxSpeed; aiPath.destination = new Vector3(worldPosition.x, worldPosition.y, 0); } } + public delegate void FollowerPickupHandler(); + public event FollowerPickupHandler OnPickupArrived; + public event FollowerPickupHandler OnPickupReturned; + private Coroutine pickupCoroutine; + + // Command follower to go to a specific point and return to player + public void GoToPointAndReturn(Vector2 itemPosition, Transform playerTransform) + { + if (pickupCoroutine != null) + StopCoroutine(pickupCoroutine); + if (aiPath != null) + aiPath.maxSpeed = followerMaxSpeed; + pickupCoroutine = StartCoroutine(PickupSequence(itemPosition, playerTransform)); + } + + private System.Collections.IEnumerator PickupSequence(Vector2 itemPosition, Transform playerTransform) + { + isManualFollowing = false; + if (aiPath != null) + { + aiPath.enabled = true; + aiPath.maxSpeed = followerMaxSpeed; + aiPath.destination = new Vector3(itemPosition.x, itemPosition.y, 0); + } + // Wait until follower reaches item (2D distance) + while (Vector2.Distance(new Vector2(transform.position.x, transform.position.y), new Vector2(itemPosition.x, itemPosition.y)) > stopThreshold) + { + yield return null; + } + OnPickupArrived?.Invoke(); + // Wait briefly, then return to player + yield return new WaitForSeconds(0.2f); + if (aiPath != null && playerTransform != null) + { + aiPath.maxSpeed = followerMaxSpeed; + aiPath.destination = playerTransform.position; + } + // Wait until follower returns to player (2D distance) + while (playerTransform != null && Vector2.Distance(new Vector2(transform.position.x, transform.position.y), new Vector2(playerTransform.position.x, playerTransform.position.y)) > stopThreshold) + { + yield return null; + } + OnPickupReturned?.Invoke(); + // Reset follower speed to normal after pickup + followerMaxSpeed = defaultFollowerMaxSpeed; + if (aiPath != null) + aiPath.maxSpeed = followerMaxSpeed; + isManualFollowing = true; + if (aiPath != null) + aiPath.enabled = false; + pickupCoroutine = null; + } + void OnDrawGizmos() { if (debugDrawTarget && Application.isPlaying) diff --git a/Assets/Scripts/GameManager.cs b/Assets/Scripts/GameManager.cs new file mode 100644 index 00000000..5786a779 --- /dev/null +++ b/Assets/Scripts/GameManager.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +public class GameManager : MonoBehaviour +{ + private static GameManager _instance; + public static GameManager Instance + { + get + { + if (_instance == null) + { + _instance = FindAnyObjectByType(); + if (_instance == null) + { + var go = new GameObject("GameManager"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + } + } + return _instance; + } + } + + [Header("Game Settings")] + public GameSettings gameSettings; + + void Awake() + { + _instance = this; + DontDestroyOnLoad(gameObject); + } + + public float PlayerStopDistance => gameSettings != null ? gameSettings.playerStopDistance : 1.0f; + public float FollowerPickupDelay => gameSettings != null ? gameSettings.followerPickupDelay : 0.2f; + // Add more accessors as needed +} diff --git a/Assets/Scripts/GameManager.cs.meta b/Assets/Scripts/GameManager.cs.meta new file mode 100644 index 00000000..e343553d --- /dev/null +++ b/Assets/Scripts/GameManager.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: b9333cd9ca0e44769ef1913d10231047 +timeCreated: 1756933142 \ No newline at end of file diff --git a/Assets/Scripts/GameSettings.cs b/Assets/Scripts/GameSettings.cs new file mode 100644 index 00000000..0dcf98e6 --- /dev/null +++ b/Assets/Scripts/GameSettings.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "GameSettings", menuName = "AppleHills/GameSettings", order = 1)] +public class GameSettings : ScriptableObject +{ + [Header("Interactions")] + public float playerStopDistance = 6.0f; + public float followerPickupDelay = 0.2f; + // Add other settings here as needed +} + diff --git a/Assets/Scripts/GameSettings.cs.meta b/Assets/Scripts/GameSettings.cs.meta new file mode 100644 index 00000000..aba7bd69 --- /dev/null +++ b/Assets/Scripts/GameSettings.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: e4ec438b455a4044957501c2c66a6f4b +timeCreated: 1756933137 \ No newline at end of file diff --git a/Assets/Scripts/LevelSwitch.cs b/Assets/Scripts/LevelSwitch.cs index f1b0d287..6498e779 100644 --- a/Assets/Scripts/LevelSwitch.cs +++ b/Assets/Scripts/LevelSwitch.cs @@ -7,8 +7,12 @@ public class LevelSwitch : MonoBehaviour public SpriteRenderer iconRenderer; private Interactable interactable; + private bool _isActive = true; + void Awake() { + _isActive = true; + if (iconRenderer == null) iconRenderer = GetComponent(); @@ -51,11 +55,12 @@ public class LevelSwitch : MonoBehaviour private async void OnInteracted() { Debug.Log($"LevelSwitch.OnInteracted: Switching to level {switchData?.targetLevelSceneName}"); - if (switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName)) + if (switchData != null && !string.IsNullOrEmpty(switchData.targetLevelSceneName) && _isActive) { // Optionally: show loading UI here var progress = new Progress(p => Debug.Log($"Loading progress: {p * 100:F0}%")); await SceneManagerService.Instance.SwitchSceneAsync(switchData.targetLevelSceneName, progress); + _isActive = false; // Optionally: hide loading UI here } } diff --git a/Assets/Scripts/Pickup.cs b/Assets/Scripts/Pickup.cs index 9390e05d..fae51e7b 100644 --- a/Assets/Scripts/Pickup.cs +++ b/Assets/Scripts/Pickup.cs @@ -6,6 +6,8 @@ public class Pickup : MonoBehaviour public SpriteRenderer iconRenderer; private Interactable interactable; + private bool pickupInProgress = false; + void Awake() { if (iconRenderer == null) @@ -33,6 +35,23 @@ public class Pickup : MonoBehaviour iconRenderer = GetComponent(); ApplyItemData(); } + + void OnDrawGizmos() + { + // Get stop distance from GameManager or default + float playerStopDistance = GameManager.Instance != null ? GameManager.Instance.PlayerStopDistance : 1.0f; + // Draw stop distance circle around pickup + Gizmos.color = Color.yellow; + Gizmos.DrawWireSphere(transform.position, playerStopDistance); + // Draw stop point (where player is told to move) + GameObject playerObj = GameObject.FindGameObjectWithTag("Player"); + if (playerObj != null) + { + Vector3 stopPoint = transform.position + (playerObj.transform.position - transform.position).normalized * playerStopDistance; + Gizmos.color = Color.cyan; + Gizmos.DrawSphere(stopPoint, 0.15f); + } + } #endif public void ApplyItemData() @@ -48,8 +67,56 @@ public class Pickup : MonoBehaviour private void OnInteracted() { - Debug.Log($"[Pickup] OnInteracted: Picked up {itemData?.itemName}"); - // TODO: Add item to inventory manager here - Destroy(gameObject); + if (pickupInProgress) return; + pickupInProgress = true; + // Find player and follower controllers + var playerObj = GameObject.FindGameObjectWithTag("Player"); + var followerObj = GameObject.FindGameObjectWithTag("Pulver"); + if (playerObj == null || followerObj == null) + { + Debug.LogWarning("Pickup: Player or Follower not found."); + pickupInProgress = false; + return; + } + var playerController = playerObj.GetComponent(); + var followerController = followerObj.GetComponent(); + if (playerController == null || followerController == null) + { + Debug.LogWarning("Pickup: PlayerTouchController or FollowerController missing."); + pickupInProgress = false; + return; + } + // Get settings from GameManager + float playerStopDistance = GameManager.Instance != null ? GameManager.Instance.PlayerStopDistance : 1.0f; + float followerPickupDelay = GameManager.Instance != null ? GameManager.Instance.FollowerPickupDelay : 0.2f; + // Subscribe to player arrival event + void OnPlayerArrived() + { + playerController.OnArrivedAtTarget -= OnPlayerArrived; + // After player arrives, dispatch follower after delay + StartCoroutine(DispatchFollower()); + } + System.Collections.IEnumerator DispatchFollower() + { + yield return new WaitForSeconds(followerPickupDelay); + // Subscribe to follower events + followerController.OnPickupArrived += OnFollowerArrived; + followerController.OnPickupReturned += OnFollowerReturned; + followerController.GoToPointAndReturn(transform.position, playerObj.transform); + } + void OnFollowerArrived() + { + followerController.OnPickupArrived -= OnFollowerArrived; + // Optionally: play pickup animation, etc. + } + void OnFollowerReturned() + { + followerController.OnPickupReturned -= OnFollowerReturned; + pickupInProgress = false; + Destroy(gameObject); + } + playerController.OnArrivedAtTarget += OnPlayerArrived; + Vector3 stopPoint = transform.position + (playerObj.transform.position - transform.position).normalized * playerStopDistance; + playerController.MoveToAndNotify(stopPoint); } } diff --git a/Assets/Scripts/PlayerTouchController.cs b/Assets/Scripts/PlayerTouchController.cs index 279a8dc6..484b0fec 100644 --- a/Assets/Scripts/PlayerTouchController.cs +++ b/Assets/Scripts/PlayerTouchController.cs @@ -21,6 +21,11 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer private Animator animator; private Transform artTransform; + public delegate void ArrivedAtTargetHandler(); + public event ArrivedAtTargetHandler OnArrivedAtTarget; + private Coroutine moveToCoroutine; + private bool interruptMoveTo = false; + void Awake() { rb3d = GetComponent(); @@ -56,6 +61,8 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer public void OnTouchPress(Vector2 worldPosition) { + // If moving to pickup, interrupt + InterruptMoveTo(); Debug.Log($"PlayerTouchController.OnTouchPress received worldPosition: {worldPosition}"); SetTargetPosition(worldPosition); } @@ -93,4 +100,48 @@ public class PlayerTouchController : MonoBehaviour, ITouchInputConsumer } // Remove FixedUpdate and MoveTowardsTarget, as AIPath handles movement + + // Move to a target position, notify when arrived + public void MoveToAndNotify(Vector3 target) + { + if (moveToCoroutine != null) + { + StopCoroutine(moveToCoroutine); + } + interruptMoveTo = false; + moveToCoroutine = StartCoroutine(MoveToTargetCoroutine(target)); + } + + public void InterruptMoveTo() + { + interruptMoveTo = true; + } + + private System.Collections.IEnumerator MoveToTargetCoroutine(Vector3 target) + { + hasTarget = true; + targetPosition = target; + if (aiPath != null) + { + aiPath.destination = target; + } + while (!interruptMoveTo) + { + // 2D distance calculation (ignore z) + Vector2 current2D = new Vector2(transform.position.x, transform.position.y); + Vector2 target2D = new Vector2(target.x, target.y); + float dist = Vector2.Distance(current2D, target2D); + if (dist <= stopDistance + 0.2f) + { + break; + } + yield return null; + } + hasTarget = false; + moveToCoroutine = null; + if (!interruptMoveTo) + { + OnArrivedAtTarget?.Invoke(); + } + } } diff --git a/Assets/Scripts/SceneManagerService.cs b/Assets/Scripts/SceneManagerService.cs index c428bd5e..e29a90f8 100644 --- a/Assets/Scripts/SceneManagerService.cs +++ b/Assets/Scripts/SceneManagerService.cs @@ -6,7 +6,24 @@ using UnityEngine.SceneManagement; public class SceneManagerService : MonoBehaviour { - public static SceneManagerService Instance { get; private set; } + private static SceneManagerService _instance; + public static SceneManagerService Instance + { + get + { + if (_instance == null) + { + _instance = FindAnyObjectByType(); + if (_instance == null) + { + var go = new GameObject("SceneManagerService"); + _instance = go.AddComponent(); + DontDestroyOnLoad(go); + } + } + return _instance; + } + } // Events for scene lifecycle public event Action SceneLoadStarted; @@ -21,12 +38,7 @@ public class SceneManagerService : MonoBehaviour void Awake() { - if (Instance != null && Instance != this) - { - Destroy(gameObject); - return; - } - Instance = this; + _instance = this; DontDestroyOnLoad(gameObject); } diff --git a/ProjectSettings/Physics2DSettings.asset b/ProjectSettings/Physics2DSettings.asset index 4500a1b1..dd2a701b 100644 --- a/ProjectSettings/Physics2DSettings.asset +++ b/ProjectSettings/Physics2DSettings.asset @@ -53,4 +53,4 @@ Physics2DSettings: m_ReuseCollisionCallbacks: 1 m_AutoSyncTransforms: 0 m_GizmoOptions: 10 - m_LayerCollisionMatrix: fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffff7fffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + m_LayerCollisionMatrix: fffffffffffffffffffffffffffffffffffffffffffffffffffefffffffcffff3fffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset index 2389b26d..7a912a38 100644 --- a/ProjectSettings/TagManager.asset +++ b/ProjectSettings/TagManager.asset @@ -5,6 +5,7 @@ TagManager: serializedVersion: 3 tags: - CharacterArt + - Pulver layers: - Default - TransparentFX