pooper_minigame (#62)
Co-authored-by: Michal Pikulski <michal.a.pikulski@gmail.com> Reviewed-on: #62
This commit is contained in:
33
Assets/Scripts/Interactions/BoosterGlowEffect.cs
Normal file
33
Assets/Scripts/Interactions/BoosterGlowEffect.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Simple glow effect component for booster pack pickups.
|
||||
/// Attach to a GameObject with a SpriteRenderer for basic glow visual.
|
||||
/// The BoosterPackPickup will handle the scale animation.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(SpriteRenderer))]
|
||||
public class BoosterGlowEffect : MonoBehaviour
|
||||
{
|
||||
[Header("Glow Settings")]
|
||||
[SerializeField] private Color glowColor = Color.yellow;
|
||||
[SerializeField] private float baseAlpha = 0.5f;
|
||||
|
||||
private SpriteRenderer spriteRenderer;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
spriteRenderer = GetComponent<SpriteRenderer>();
|
||||
|
||||
// Apply glow color with alpha
|
||||
Color color = glowColor;
|
||||
color.a = baseAlpha;
|
||||
spriteRenderer.color = color;
|
||||
|
||||
// Set sorting order to be behind the item
|
||||
spriteRenderer.sortingOrder = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Interactions/BoosterGlowEffect.cs.meta
Normal file
3
Assets/Scripts/Interactions/BoosterGlowEffect.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f6488b58253b4e6789103e341090ca2f
|
||||
timeCreated: 1763639769
|
||||
299
Assets/Scripts/Interactions/BoosterPackPickup.cs
Normal file
299
Assets/Scripts/Interactions/BoosterPackPickup.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using UnityEngine;
|
||||
using System.Collections;
|
||||
using Unity.Cinemachine;
|
||||
using Data.CardSystem;
|
||||
using Pixelplacement;
|
||||
using Core;
|
||||
using UI;
|
||||
|
||||
namespace Interactions
|
||||
{
|
||||
/// <summary>
|
||||
/// Special pickup that plays a fancy sequence when collected:
|
||||
/// - Follower picks up normally
|
||||
/// - Pauses follower movement
|
||||
/// - Zooms camera in
|
||||
/// - Grows/pulses the booster pack
|
||||
/// - Animates to backpack icon
|
||||
/// - Gives player a booster pack
|
||||
/// - Restores camera and resumes movement
|
||||
/// </summary>
|
||||
public class BoosterPackPickup : Pickup
|
||||
{
|
||||
[Header("Booster Pack Sequence")]
|
||||
[SerializeField] private GameObject glowVisualPrefab;
|
||||
[SerializeField] private CinemachineCamera zoomCamera;
|
||||
[SerializeField] private int boosterPackCount = 1;
|
||||
|
||||
[Header("Sequence Timing")]
|
||||
[SerializeField] private float cameraBlendWait = 0.3f;
|
||||
[SerializeField] private float growDuration = 0.25f;
|
||||
[SerializeField] private float pulseDuration = 0.3f;
|
||||
[SerializeField] private int pulseCount = 3;
|
||||
[SerializeField] private float disappearDuration = 0.5f;
|
||||
|
||||
[Header("Animation Settings")]
|
||||
[SerializeField] private float growScale = 1.5f;
|
||||
[SerializeField] private float pulseScale = 1.2f;
|
||||
|
||||
private GameObject glowInstance;
|
||||
private bool sequencePlaying;
|
||||
|
||||
protected override bool DoInteraction()
|
||||
{
|
||||
// Let the normal pickup flow happen first
|
||||
bool success = base.DoInteraction();
|
||||
|
||||
// If pickup was successful and we're not already playing the sequence, start it
|
||||
// IMPORTANT: We start the coroutine on the FollowerController, not on this object,
|
||||
// because this object gets disabled immediately after pickup
|
||||
if (success && !sequencePlaying)
|
||||
{
|
||||
var follower = FollowerController.FindInstance();
|
||||
if (follower != null)
|
||||
{
|
||||
follower.StartCoroutine(BoosterSequence(follower));
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("[BoosterPackPickup] No follower found, cannot start sequence");
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
private IEnumerator BoosterSequence(FollowerController follower)
|
||||
{
|
||||
sequencePlaying = true;
|
||||
|
||||
// IMPORTANT: Disable all children on the original pickup GameObject
|
||||
// This prevents glow effects and other child objects from appearing in Pulver's hand
|
||||
foreach (Transform child in transform)
|
||||
{
|
||||
child.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
// Wait one frame to ensure pickup is fully processed
|
||||
yield return null;
|
||||
|
||||
// Verify follower still exists (safety check)
|
||||
if (follower == null)
|
||||
{
|
||||
Logging.Warning("[BoosterPackPickup] Follower destroyed during sequence, aborting");
|
||||
sequencePlaying = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
Transform heldItemTransform = follower.GetHeldItemTransform();
|
||||
if (heldItemTransform == null)
|
||||
{
|
||||
Logging.Warning("[BoosterPackPickup] No held item transform found, skipping sequence");
|
||||
sequencePlaying = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
// 1. Pause follower movement
|
||||
follower.PauseMovement();
|
||||
|
||||
// 2. Activate zoom camera if assigned
|
||||
if (zoomCamera != null)
|
||||
{
|
||||
// Unparent the camera from the booster pack (if it's parented)
|
||||
zoomCamera.transform.SetParent(null);
|
||||
|
||||
// Position camera at follower's location
|
||||
zoomCamera.transform.position = new Vector3(
|
||||
follower.transform.position.x,
|
||||
follower.transform.position.y,
|
||||
zoomCamera.transform.position.z
|
||||
);
|
||||
|
||||
// Make the blend instant by setting a custom blend hint
|
||||
var brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
CinemachineBlendDefinition originalBlend = default;
|
||||
if (brain != null)
|
||||
{
|
||||
originalBlend = brain.DefaultBlend;
|
||||
brain.DefaultBlend = new CinemachineBlendDefinition(CinemachineBlendDefinition.Styles.EaseInOut, 1);
|
||||
}
|
||||
|
||||
zoomCamera.Priority = 20;
|
||||
zoomCamera.gameObject.SetActive(true);
|
||||
|
||||
// Wait a frame for the cut to take effect
|
||||
yield return null;
|
||||
|
||||
// Restore original blend settings
|
||||
if (brain != null)
|
||||
{
|
||||
brain.DefaultBlend = originalBlend;
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Grow animation (no glow during this)
|
||||
Vector3 originalScale = heldItemTransform.localScale;
|
||||
Tween.LocalScale(heldItemTransform, originalScale * growScale, growDuration, 0f, Tween.EaseOutBack);
|
||||
yield return new WaitForSeconds(growDuration);
|
||||
|
||||
// 4. Instantiate and pulse glow
|
||||
if (glowVisualPrefab != null)
|
||||
{
|
||||
glowInstance = Instantiate(glowVisualPrefab, heldItemTransform);
|
||||
glowInstance.transform.localPosition = Vector3.zero;
|
||||
glowInstance.transform.localScale = Vector3.one;
|
||||
|
||||
for (int i = 0; i < pulseCount; i++)
|
||||
{
|
||||
Tween.LocalScale(glowInstance.transform, Vector3.one * pulseScale, pulseDuration, 0f, Tween.EaseIn);
|
||||
yield return new WaitForSeconds(pulseDuration);
|
||||
Tween.LocalScale(glowInstance.transform, Vector3.one, pulseDuration, 0f, Tween.EaseInOut);
|
||||
yield return new WaitForSeconds(pulseDuration);
|
||||
}
|
||||
|
||||
// Delete glow before flying to button
|
||||
Destroy(glowInstance);
|
||||
glowInstance = null;
|
||||
}
|
||||
|
||||
// 5. Disappear to scrapbook button (backpack icon) - straight line movement
|
||||
GameObject scrabookButton = PlayerHudManager.Instance?.GetScrabookButton();
|
||||
if (scrabookButton != null)
|
||||
{
|
||||
// Get start position in world space
|
||||
Vector3 startPos = heldItemTransform.position;
|
||||
|
||||
// Convert UI button position to world space
|
||||
RectTransform buttonRect = scrabookButton.GetComponent<RectTransform>();
|
||||
Vector3 targetWorldPos;
|
||||
|
||||
if (buttonRect != null)
|
||||
{
|
||||
// UI element - get screen position correctly
|
||||
Vector3[] corners = new Vector3[4];
|
||||
buttonRect.GetWorldCorners(corners);
|
||||
|
||||
// Get center of the button in screen space
|
||||
Vector3 buttonCenter = (corners[0] + corners[2]) / 2f;
|
||||
|
||||
// For Screen Space Overlay, the corners are already in screen space
|
||||
Canvas canvas = buttonRect.GetComponentInParent<Canvas>();
|
||||
Vector3 buttonScreenPos;
|
||||
|
||||
if (canvas != null && canvas.renderMode == RenderMode.ScreenSpaceOverlay)
|
||||
{
|
||||
// Already in screen space
|
||||
buttonScreenPos = buttonCenter;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert from world to screen space
|
||||
buttonScreenPos = RectTransformUtility.WorldToScreenPoint(canvas?.worldCamera ?? Camera.main, buttonCenter);
|
||||
}
|
||||
|
||||
// Convert screen position to world space at the same Z as the booster pack
|
||||
targetWorldPos = Camera.main.ScreenToWorldPoint(new Vector3(buttonScreenPos.x, buttonScreenPos.y, Mathf.Abs(Camera.main.transform.position.z - startPos.z)));
|
||||
|
||||
Logging.Debug($"[BoosterPackPickup] Button screen pos: {buttonScreenPos}, converted world pos: {targetWorldPos}");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not a UI element, use direct world position
|
||||
targetWorldPos = scrabookButton.transform.position;
|
||||
}
|
||||
|
||||
Logging.Debug($"[BoosterPackPickup] Flying from {startPos} to {targetWorldPos} (button: {scrabookButton.name})");
|
||||
|
||||
// Use custom tween with linear interpolation for straight line
|
||||
float elapsed = 0f;
|
||||
Vector3 startScale = heldItemTransform.localScale;
|
||||
|
||||
while (elapsed < disappearDuration)
|
||||
{
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / disappearDuration);
|
||||
|
||||
// Linear interpolation for straight line movement
|
||||
heldItemTransform.position = Vector3.Lerp(startPos, targetWorldPos, t);
|
||||
|
||||
// Ease in for scale (gets smaller as it approaches)
|
||||
float scaleT = t * t; // Simple ease-in curve
|
||||
heldItemTransform.localScale = Vector3.Lerp(startScale, Vector3.zero, scaleT);
|
||||
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// Ensure final position/scale
|
||||
heldItemTransform.position = targetWorldPos;
|
||||
heldItemTransform.localScale = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("[BoosterPackPickup] No scrapbook button found from PlayerHudManager, skipping fly-to animation");
|
||||
}
|
||||
|
||||
// 7. Give booster pack to player
|
||||
if (CardSystemManager.Instance != null)
|
||||
{
|
||||
CardSystemManager.Instance.AddBoosterPack(boosterPackCount);
|
||||
Logging.Debug($"[BoosterPackPickup] Gave {boosterPackCount} booster pack(s) to player");
|
||||
}
|
||||
else
|
||||
{
|
||||
Logging.Warning("[BoosterPackPickup] CardSystemManager not found, cannot give booster pack");
|
||||
}
|
||||
|
||||
// 8. Cleanup glow
|
||||
if (glowInstance != null)
|
||||
{
|
||||
Destroy(glowInstance);
|
||||
}
|
||||
|
||||
// 9. Blend back to main camera and cleanup
|
||||
if (zoomCamera != null)
|
||||
{
|
||||
// Lower priority to blend back to main camera
|
||||
zoomCamera.Priority = 0;
|
||||
|
||||
// Wait for blend back to complete (using default blend settings)
|
||||
var brain = Camera.main?.GetComponent<CinemachineBrain>();
|
||||
if (brain != null && brain.IsBlending)
|
||||
{
|
||||
// Wait for the blend to finish
|
||||
while (brain.IsBlending)
|
||||
{
|
||||
yield return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// If not blending or no brain, just wait a short moment
|
||||
yield return new WaitForSeconds(0.3f);
|
||||
}
|
||||
|
||||
// Destroy the zoom camera
|
||||
Destroy(zoomCamera.gameObject);
|
||||
}
|
||||
|
||||
// 10. Clear the follower's held item since we "consumed" it
|
||||
follower.ClearHeldItem();
|
||||
|
||||
// 11. Resume follower movement
|
||||
follower.ResumeMovement();
|
||||
|
||||
sequencePlaying = false;
|
||||
}
|
||||
|
||||
internal override void OnManagedDestroy()
|
||||
{
|
||||
base.OnManagedDestroy();
|
||||
|
||||
// Cleanup glow if still exists
|
||||
if (glowInstance != null)
|
||||
{
|
||||
Destroy(glowInstance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
3
Assets/Scripts/Interactions/BoosterPackPickup.cs.meta
Normal file
3
Assets/Scripts/Interactions/BoosterPackPickup.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11629418bd2d44fa9da229ad62c04332
|
||||
timeCreated: 1763639641
|
||||
Reference in New Issue
Block a user