diff --git a/Assets/Prefabs/Minigames/FortFight/Projectiles/TrashPiece.prefab b/Assets/Prefabs/Minigames/FortFight/Projectiles/TrashPiece.prefab
index d7f3edc2..1722222c 100644
--- a/Assets/Prefabs/Minigames/FortFight/Projectiles/TrashPiece.prefab
+++ b/Assets/Prefabs/Minigames/FortFight/Projectiles/TrashPiece.prefab
@@ -106,8 +106,8 @@ Rigidbody2D:
m_UseFullKinematicContacts: 0
m_UseAutoMass: 0
m_Mass: 1
- m_LinearDamping: 0
- m_AngularDamping: 0.05
+ m_LinearDamping: 1
+ m_AngularDamping: 1
m_GravityScale: 1
m_Material: {fileID: 0}
m_IncludeLayers:
diff --git a/Assets/Scenes/MiniGames/FortFight.unity b/Assets/Scenes/MiniGames/FortFight.unity
index ed953a92..5a5dceb7 100644
--- a/Assets/Scenes/MiniGames/FortFight.unity
+++ b/Assets/Scenes/MiniGames/FortFight.unity
@@ -2712,7 +2712,7 @@ GameObject:
- component: {fileID: 841922114}
- component: {fileID: 841922117}
- component: {fileID: 841922116}
- - component: {fileID: 841922115}
+ - component: {fileID: 841922118}
m_Layer: 0
m_Name: SlingShot
m_TagString: Untagged
@@ -2737,21 +2737,6 @@ Transform:
- {fileID: 1448546925}
m_Father: {fileID: 1009687014}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!114 &841922115
-MonoBehaviour:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 841922113}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: b1e26667c6d4415f8dc51e4a58ba9479, type: 3}
- m_Name:
- m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.Core.TrajectoryPreview
- simulationSteps: 50
- lineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
- lineWidth: 0.1
--- !u!120 &841922116
LineRenderer:
serializedVersion: 2
@@ -2877,8 +2862,25 @@ MonoBehaviour:
maxDragDistanceOverride: 0
maxForceOverride: 0
launchAnchor: {fileID: 1668202570}
+ trajectoryPreview: {fileID: 841922118}
showDebugLogs: 1
- trajectoryPreview: {fileID: 841922115}
+--- !u!114 &841922118
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 841922113}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b86a4cd82d4a47de9d1e4d97ffd01f5e, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: AppleHillsScripts::Common.Visual.TrajectoryPreview
+ trajectoryPoints: 50
+ timeStep: 0.1
+ groundLevel: -10
+ lineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
+ lineWidth: 0.1
--- !u!1 &846792101
GameObject:
m_ObjectHideFlags: 0
@@ -4365,7 +4367,7 @@ GameObject:
- component: {fileID: 1460473367}
- component: {fileID: 1460473370}
- component: {fileID: 1460473369}
- - component: {fileID: 1460473368}
+ - component: {fileID: 1460473371}
m_Layer: 0
m_Name: SlingShot
m_TagString: Untagged
@@ -4390,21 +4392,6 @@ Transform:
- {fileID: 56461670}
m_Father: {fileID: 799036564}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
---- !u!114 &1460473368
-MonoBehaviour:
- m_ObjectHideFlags: 0
- m_CorrespondingSourceObject: {fileID: 0}
- m_PrefabInstance: {fileID: 0}
- m_PrefabAsset: {fileID: 0}
- m_GameObject: {fileID: 1460473366}
- m_Enabled: 1
- m_EditorHideFlags: 0
- m_Script: {fileID: 11500000, guid: b1e26667c6d4415f8dc51e4a58ba9479, type: 3}
- m_Name:
- m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.Core.TrajectoryPreview
- simulationSteps: 30
- lineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
- lineWidth: 0.1
--- !u!120 &1460473369
LineRenderer:
serializedVersion: 2
@@ -4530,8 +4517,25 @@ MonoBehaviour:
maxDragDistanceOverride: 0
maxForceOverride: 0
launchAnchor: {fileID: 497509525}
+ trajectoryPreview: {fileID: 1460473371}
showDebugLogs: 1
- trajectoryPreview: {fileID: 1460473368}
+--- !u!114 &1460473371
+MonoBehaviour:
+ m_ObjectHideFlags: 0
+ m_CorrespondingSourceObject: {fileID: 0}
+ m_PrefabInstance: {fileID: 0}
+ m_PrefabAsset: {fileID: 0}
+ m_GameObject: {fileID: 1460473366}
+ m_Enabled: 1
+ m_EditorHideFlags: 0
+ m_Script: {fileID: 11500000, guid: b86a4cd82d4a47de9d1e4d97ffd01f5e, type: 3}
+ m_Name:
+ m_EditorClassIdentifier: AppleHillsScripts::Common.Visual.TrajectoryPreview
+ trajectoryPoints: 50
+ timeStep: 0.1
+ groundLevel: -10
+ lineColor: {r: 1, g: 0.92156863, b: 0.015686275, a: 1}
+ lineWidth: 0.1
--- !u!1 &1543340062
GameObject:
m_ObjectHideFlags: 0
diff --git a/Assets/Scripts/Common/Input/DragLaunchController.cs b/Assets/Scripts/Common/Input/DragLaunchController.cs
index 370bb959..743769df 100644
--- a/Assets/Scripts/Common/Input/DragLaunchController.cs
+++ b/Assets/Scripts/Common/Input/DragLaunchController.cs
@@ -6,6 +6,21 @@ using UnityEngine;
namespace Common.Input
{
+ ///
+ /// Cached launch parameters calculated during drag.
+ /// Avoids recalculating force/direction multiple times.
+ ///
+ public struct LaunchParameters
+ {
+ public Vector2 Direction;
+ public float Force;
+ public float DragDistance;
+ public float DragRatio;
+ public float Mass;
+
+ public bool IsValid => Force > 0f && DragDistance > 0f;
+ }
+
///
/// Base class for drag-to-launch mechanics (Angry Birds style).
/// Provides core drag logic, force calculation, and input handling.
@@ -81,6 +96,9 @@ namespace Common.Input
[Tooltip("Launch anchor point (spawn/slingshot position)")]
[SerializeField] protected Transform launchAnchor;
+ [Tooltip("Trajectory preview component (auto-found if not assigned)")]
+ [SerializeField] protected Common.Visual.TrajectoryPreview trajectoryPreview;
+
[Header("Debug")]
[SerializeField] protected bool showDebugLogs;
@@ -98,7 +116,10 @@ namespace Common.Input
private bool _isDragging;
private Vector2 _dragStartPosition;
private bool _isEnabled = false;
- private bool _isRegistered = false;
+ private bool _isRegisteredForInput = false;
+
+ // Cached launch parameters - calculated once during drag, used for both preview and launch
+ private LaunchParameters _cachedLaunchParams;
public bool IsDragging => _isDragging;
public bool IsEnabled => _isEnabled;
@@ -135,10 +156,10 @@ namespace Common.Input
_isEnabled = true;
// Register with InputManager as override consumer
- if (InputManager.Instance != null && !_isRegistered)
+ if (InputManager.Instance != null && !_isRegisteredForInput)
{
InputManager.Instance.RegisterOverrideConsumer(this);
- _isRegistered = true;
+ _isRegisteredForInput = true;
if (showDebugLogs) Logging.Debug($"[{GetType().Name}] Registered with InputManager");
}
@@ -157,10 +178,10 @@ namespace Common.Input
_isDragging = false;
// Unregister from InputManager
- if (InputManager.Instance != null && _isRegistered)
+ if (InputManager.Instance != null && _isRegisteredForInput)
{
InputManager.Instance.UnregisterOverrideConsumer(this);
- _isRegistered = false;
+ _isRegisteredForInput = false;
if (showDebugLogs) Logging.Debug($"[{GetType().Name}] Unregistered from InputManager");
}
@@ -220,29 +241,19 @@ namespace Common.Input
///
protected virtual void UpdateDrag(Vector2 currentWorldPosition)
{
- // Calculate drag vector from anchor to current drag position
- // Pull back (away from anchor) = launch forward (toward anchor direction)
- Vector2 dragVector = _dragStartPosition - currentWorldPosition;
-
- // Calculate force and direction
- float dragDistance = dragVector.magnitude;
- float dragRatio = Mathf.Clamp01(dragDistance / MaxDragDistance);
-
- // Use config to calculate force with multipliers
- float force = Config?.CalculateForce(dragDistance, dragRatio) ?? (dragRatio * MaxForce);
- Vector2 direction = dragVector.normalized;
- float mass = GetProjectileMass();
+ // Calculate launch parameters once and cache
+ _cachedLaunchParams = CalculateLaunchParameters(currentWorldPosition);
// Warn if mass is zero or invalid
- if (mass <= 0f && showDebugLogs)
+ if (_cachedLaunchParams.Mass <= 0f && showDebugLogs)
{
- Logging.Warning($"[{GetType().Name}] Projectile mass is {mass}! Trajectory calculation will be inaccurate. Override GetProjectileMass().");
+ Logging.Warning($"[{GetType().Name}] Projectile mass is {_cachedLaunchParams.Mass}! Trajectory calculation will be inaccurate. Override GetProjectileMass().");
}
- // Update visuals with mass parameter
- UpdateVisuals(currentWorldPosition, direction, force, dragDistance, mass);
+ // Update visuals with cached parameters
+ UpdateVisuals(currentWorldPosition, _cachedLaunchParams);
- OnDragUpdate?.Invoke(currentWorldPosition, direction, force);
+ OnDragUpdate?.Invoke(currentWorldPosition, _cachedLaunchParams.Direction, _cachedLaunchParams.Force);
}
///
@@ -255,34 +266,48 @@ namespace Common.Input
// Hide preview
HidePreview();
- // Calculate final launch parameters
+ // Recalculate final parameters (position may have changed since last UpdateDrag)
+ _cachedLaunchParams = CalculateLaunchParameters(currentWorldPosition);
+
+ OnDragEnd?.Invoke(currentWorldPosition, _cachedLaunchParams.Direction, _cachedLaunchParams.Force);
+
+ if (showDebugLogs)
+ Logging.Debug($"[{GetType().Name}] Launching with force {_cachedLaunchParams.Force:F2}");
+ PerformLaunch(_cachedLaunchParams.Direction, _cachedLaunchParams.Force);
+ OnLaunch?.Invoke(_cachedLaunchParams.Direction, _cachedLaunchParams.Force);
+ }
+
+ ///
+ /// Calculate launch parameters from current drag position.
+ /// Caches results to avoid recalculating force multiple times.
+ ///
+ private LaunchParameters CalculateLaunchParameters(Vector2 currentWorldPosition)
+ {
+ // Calculate drag vector from anchor to current drag position
+ // Pull back (away from anchor) = launch forward (toward anchor direction)
Vector2 dragVector = _dragStartPosition - currentWorldPosition;
+
+ // Calculate distance and ratio
float dragDistance = dragVector.magnitude;
float dragRatio = Mathf.Clamp01(dragDistance / MaxDragDistance);
- // Use config to calculate force with multipliers
+ // Calculate force using config
float force = Config?.CalculateForce(dragDistance, dragRatio) ?? (dragRatio * MaxForce);
- Vector2 direction = dragVector.normalized;
- // Get minimum force from config
- float minForce = Config?.GetMinForce() ?? (MaxForce * 0.1f);
+ // Normalize direction
+ Vector2 direction = dragDistance > 0.01f ? dragVector.normalized : Vector2.zero;
- if (showDebugLogs)
- Logging.Debug($"[{GetType().Name}] Drag ended - Force: {force:F2}, Min: {minForce:F2}, Distance: {dragDistance:F2}");
+ // Get mass from projectile
+ float mass = GetProjectileMass();
- OnDragEnd?.Invoke(currentWorldPosition, direction, force);
-
- // Launch if force exceeds minimum
- if (force >= minForce)
+ return new LaunchParameters
{
- if (showDebugLogs) Logging.Debug($"[{GetType().Name}] Launching with force {force:F2}");
- PerformLaunch(direction, force);
- OnLaunch?.Invoke(direction, force);
- }
- else
- {
- if (showDebugLogs) Logging.Debug($"[{GetType().Name}] Drag too short - force {force:F2} < min {minForce:F2}");
- }
+ Direction = direction,
+ Force = force,
+ DragDistance = dragDistance,
+ DragRatio = dragRatio,
+ Mass = mass
+ };
}
#endregion
@@ -303,15 +328,23 @@ namespace Common.Input
/// Default: Updates trajectory preview using prefab's physics properties.
/// Override for custom visuals.
///
- protected virtual void UpdateVisuals(Vector2 currentPosition, Vector2 direction, float force, float dragDistance, float mass)
+ /// Current drag position
+ /// Cached launch parameters (direction, force, etc.)
+ protected virtual void UpdateVisuals(Vector2 currentPosition, LaunchParameters launchParams)
{
- if (trajectoryPreview != null && dragDistance > 0.1f)
+ if (trajectoryPreview != null && launchParams.DragDistance > 0.1f)
{
GameObject prefab = GetProjectilePrefab();
- if (prefab != null)
- {
- trajectoryPreview.UpdateTrajectory(launchAnchor.position, direction, force, prefab);
- }
+ if (prefab == null) return;
+
+ // Get gravity from prefab's Rigidbody2D gravityScale
+ var rb = prefab.GetComponent();
+ float gravityScale = rb != null ? rb.gravityScale : 1f;
+ float gravity = Physics2D.gravity.magnitude * gravityScale;
+
+ // Use mass from settings (already in launchParams)
+ trajectoryPreview.UpdateTrajectory(launchAnchor.position, launchParams.Direction,
+ launchParams.Force, launchParams.Mass, gravity);
}
}
@@ -337,52 +370,14 @@ namespace Common.Input
#endregion
- #region Virtual Methods - Optional Override
+ #region Abstract Methods - Physics Configuration
///
/// Get projectile mass for trajectory calculation.
- /// Reads from the prefab's Rigidbody2D component.
- /// Subclasses can override for custom behavior (e.g., if mass changes dynamically).
+ /// MUST read from settings - the same source that Initialize() uses.
+ /// Subclasses implement to return the actual runtime mass.
///
- protected virtual float GetProjectileMass()
- {
- GameObject prefab = GetProjectilePrefab();
- if (prefab == null)
- {
- if (showDebugLogs)
- Logging.Warning($"[{GetType().Name}] GetProjectilePrefab() returned null!");
- return 0f;
- }
-
- var rb = prefab.GetComponent();
- if (rb == null)
- {
- if (showDebugLogs)
- Logging.Warning($"[{GetType().Name}] Projectile prefab '{prefab.name}' has no Rigidbody2D!");
- return 0f;
- }
-
- return rb.mass;
- }
-
- ///
- /// Get gravity value for trajectory calculation.
- /// Uses Physics2D.gravity.magnitude * prefab's Rigidbody2D gravityScale.
- ///
- protected virtual float GetGravity()
- {
- GameObject prefab = GetProjectilePrefab();
- if (prefab == null)
- {
- // Fallback to project gravity
- return Physics2D.gravity.magnitude;
- }
-
- var rb = prefab.GetComponent();
- float gravityScale = rb != null ? rb.gravityScale : 1f;
-
- return Physics2D.gravity.magnitude * gravityScale;
- }
+ protected abstract float GetProjectileMass();
#endregion
@@ -393,7 +388,7 @@ namespace Common.Input
base.OnManagedDestroy();
// Ensure we unregister from InputManager
- if (_isRegistered && InputManager.Instance != null)
+ if (_isRegisteredForInput && InputManager.Instance != null)
{
InputManager.Instance.UnregisterOverrideConsumer(this);
}
diff --git a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs
index 4b38f2da..b0857977 100644
--- a/Assets/Scripts/Core/Settings/SettingsInterfaces.cs
+++ b/Assets/Scripts/Core/Settings/SettingsInterfaces.cs
@@ -251,12 +251,6 @@ namespace AppleHills.Core.Settings
int FortBlockLayer { get; } // Layer index for fort blocks
int ProjectileLayer { get; } // Layer index for projectiles
- // Slingshot Settings
- float BaseLaunchForce { get; } // Base launch force multiplier
- float MinForceMultiplier { get; } // Minimum force required to launch (0-1)
- float MaxForceMultiplier { get; } // Maximum force cap (0-2, usually 1)
- float TrajectoryLockDuration { get; } // How long to show trajectory after launch
-
// Projectile Abilities
float VacuumSlideSpeed { get; } // Constant velocity for vacuum sliding (m/s)
int VacuumDestroyBlockCount { get; } // Blocks to destroy while sliding
diff --git a/Assets/Scripts/Minigames/Airplane/Core/AirplaneController.cs b/Assets/Scripts/Minigames/Airplane/Core/AirplaneController.cs
index 6d04d750..ac0c412a 100644
--- a/Assets/Scripts/Minigames/Airplane/Core/AirplaneController.cs
+++ b/Assets/Scripts/Minigames/Airplane/Core/AirplaneController.cs
@@ -44,12 +44,6 @@ namespace Minigames.Airplane.Core
[Tooltip("Gravity multiplier for arc calculation")]
[SerializeField] private float gravity = 9.81f;
- [Tooltip("Mass of the airplane")]
- [SerializeField] private float mass = 1f;
-
- [Tooltip("Maximum flight time before timeout (seconds)")]
- [SerializeField] private float maxFlightTime = 10f;
-
[Header("Visual")]
[Tooltip("Should airplane rotate to face velocity direction?")]
[SerializeField] private bool rotateToVelocity = true;
@@ -68,6 +62,10 @@ namespace Minigames.Airplane.Core
private float flightTimer = 0f;
private string lastHitTarget = null;
+ // Runtime values loaded from settings
+ private float mass;
+ private float maxFlightTime;
+
public bool IsFlying => isFlying;
public Vector2 CurrentVelocity => currentVelocity;
public string LastHitTarget => lastHitTarget;
@@ -80,6 +78,20 @@ namespace Minigames.Airplane.Core
{
base.OnManagedAwake();
+ // Load settings
+ var settings = GameManager.GetSettingsObject();
+ if (settings != null)
+ {
+ mass = settings.AirplaneMass;
+ maxFlightTime = settings.MaxFlightTime;
+ }
+ else
+ {
+ Logging.Warning("[AirplaneController] AirplaneSettings not found, using defaults!");
+ mass = 1f;
+ maxFlightTime = 10f;
+ }
+
// Cache components
rb2D = GetComponent();
airplaneCollider = GetComponent();
diff --git a/Assets/Scripts/Minigames/Airplane/Core/AirplaneLaunchController.cs b/Assets/Scripts/Minigames/Airplane/Core/AirplaneLaunchController.cs
index fdc41226..0836608d 100644
--- a/Assets/Scripts/Minigames/Airplane/Core/AirplaneLaunchController.cs
+++ b/Assets/Scripts/Minigames/Airplane/Core/AirplaneLaunchController.cs
@@ -36,6 +36,20 @@ namespace Minigames.Airplane.Core
return airplanePrefab;
}
+ protected override float GetProjectileMass()
+ {
+ var settings = GameManager.GetSettingsObject();
+ if (settings == null)
+ {
+ if (showDebugLogs)
+ Logging.Warning("[AirplaneLaunchController] AirplaneSettings not found!");
+ return 1f; // Default fallback
+ }
+
+ // Read from AirplaneSettings - same mass that AirplaneController uses
+ return settings.AirplaneMass;
+ }
+
#endregion
#region Inspector Properties
@@ -84,92 +98,8 @@ namespace Minigames.Airplane.Core
#region Visual Feedback
- protected override void ShowPreview()
- {
- // Show anchor visual
- if (anchorVisual != null)
- {
- anchorVisual.SetActive(true);
- }
-
- // Show trajectory line (will be updated during drag)
- if (trajectoryLine != null)
- {
- trajectoryLine.enabled = false; // Only show during drag
- }
-
- if (showDebugLogs) Logging.Debug("[AirplaneLaunchController] Preview shown");
- }
-
- protected override void HidePreview()
- {
- // Hide anchor visual
- if (anchorVisual != null)
- {
- anchorVisual.SetActive(false);
- }
-
- // Hide trajectory line
- if (trajectoryLine != null)
- {
- trajectoryLine.enabled = false;
- }
-
- if (showDebugLogs) Logging.Debug("[AirplaneLaunchController] Preview hidden");
- }
-
- protected override void UpdateVisuals(Vector2 currentPosition, Vector2 direction, float force, float dragDistance, float mass)
- {
- // Show trajectory line during drag
- if (trajectoryLine != null && trajectoryLine.enabled == false && dragDistance > 0.1f)
- {
- trajectoryLine.enabled = true;
- }
-
- // Update trajectory preview
- if (trajectoryLine != null && trajectoryLine.enabled)
- {
- UpdateTrajectoryPreview(direction, force, mass);
- }
- }
-
- ///
- /// Update the trajectory preview line
- ///
- private void UpdateTrajectoryPreview(Vector2 direction, float force, float mass)
- {
- if (trajectoryLine == null) return;
-
- var config = Config;
- if (config == null) return;
-
- if (mass <= 0f)
- {
- if (showDebugLogs) Logging.Warning("[AirplaneLaunchController] Cannot calculate trajectory with zero mass!");
- return;
- }
-
- Vector2 startPos = launchAnchor.position;
- float initialSpeed = force / mass;
- Vector2 velocity = direction * initialSpeed;
-
- // Get gravity from prefab's Rigidbody2D (Physics2D.gravity.magnitude * rb.gravityScale)
- float gravity = GetGravity();
-
- trajectoryLine.positionCount = config.trajectoryPoints;
-
- // Calculate trajectory points using config values
- for (int i = 0; i < config.trajectoryPoints; i++)
- {
- float time = i * config.trajectoryTimeStep;
-
- // Calculate position at this time
- float x = startPos.x + velocity.x * time;
- float y = startPos.y + velocity.y * time - 0.5f * gravity * time * time;
-
- trajectoryLine.SetPosition(i, new Vector3(x, y, 0));
- }
- }
+ // Base class handles trajectory preview via TrajectoryPreview component
+ // No custom visual feedback needed for airplane - using default implementation
#endregion
diff --git a/Assets/Scripts/Minigames/FortFight/Core/FortFightSettings.cs b/Assets/Scripts/Minigames/FortFight/Core/FortFightSettings.cs
index f9eb1fb8..df9360c9 100644
--- a/Assets/Scripts/Minigames/FortFight/Core/FortFightSettings.cs
+++ b/Assets/Scripts/Minigames/FortFight/Core/FortFightSettings.cs
@@ -126,21 +126,6 @@ namespace Minigames.FortFight.Core
[Tooltip("Downward velocity when dropping (m/s)")]
[SerializeField] private float ceilingFanDropSpeed = 20f;
- [Header("Slingshot Settings")]
- [Tooltip("Base launch force multiplier - higher values = projectiles fly farther")]
- [SerializeField] private float baseLaunchForce = 20f;
-
- [Tooltip("Minimum force multiplier (0-1, e.g. 0.1 = 10% of max force required to launch)")]
- [Range(0f, 1f)]
- [SerializeField] private float minForceMultiplier = 0.1f;
-
- [Tooltip("Maximum force multiplier (0-1, e.g. 1.0 = 100% at max drag distance)")]
- [Range(0f, 2f)]
- [SerializeField] private float maxForceMultiplier = 1f;
-
- [Tooltip("How long to keep trajectory visible after launching (seconds)")]
- [SerializeField] private float trajectoryLockDuration = 2f;
-
[Header("Physics Layers")]
[Tooltip("Layer for fort blocks - projectiles will collide with these (Default: Layer 8 'FortBlock')")]
[AppleHills.Core.Settings.Layer]
@@ -180,11 +165,6 @@ namespace Minigames.FortFight.Core
public Color DamageColorTint => damageColorTint;
- public float BaseLaunchForce => baseLaunchForce;
- public float MinForceMultiplier => minForceMultiplier;
- public float MaxForceMultiplier => maxForceMultiplier;
- public float TrajectoryLockDuration => trajectoryLockDuration;
-
public float VacuumSlideSpeed => vacuumSlideSpeed;
public int VacuumDestroyBlockCount => vacuumDestroyBlockCount;
public float VacuumBlockDamage => vacuumBlockDamage;
diff --git a/Assets/Scripts/Minigames/FortFight/Core/SlingshotController.cs b/Assets/Scripts/Minigames/FortFight/Core/SlingshotController.cs
index c13495c1..37e4bc16 100644
--- a/Assets/Scripts/Minigames/FortFight/Core/SlingshotController.cs
+++ b/Assets/Scripts/Minigames/FortFight/Core/SlingshotController.cs
@@ -16,9 +16,7 @@ namespace Minigames.FortFight.Core
{
#region Inspector Properties
- [Header("FortFight Specific")]
- [Tooltip("Trajectory preview component")]
- [SerializeField] private TrajectoryPreview trajectoryPreview;
+ // Note: trajectoryPreview is inherited from DragLaunchController base class
#endregion
@@ -86,28 +84,13 @@ namespace Minigames.FortFight.Core
{
base.OnManagedAwake();
- // Base class handles launchAnchor (previously projectileSpawnPoint)
-
- if (trajectoryPreview == null)
- {
- trajectoryPreview = GetComponent();
- }
+ // Base class handles launchAnchor and trajectoryPreview
// Set debug logging from developer settings
showDebugLogs = CachedDevSettings?.SlingshotShowDebugLogs ?? false;
}
- internal override void OnManagedStart()
- {
- base.OnManagedStart();
-
- // Hide trajectory by default
- if (trajectoryPreview != null)
- {
- trajectoryPreview.Hide();
- }
- }
-
+
#endregion
#region Override Methods
@@ -129,6 +112,19 @@ namespace Minigames.FortFight.Core
LaunchProjectile(direction, force);
}
+ protected override float GetProjectileMass()
+ {
+ if (_currentAmmo == null)
+ {
+ if (showDebugLogs)
+ Logging.Warning("[SlingshotController] No ammo selected, cannot get mass!");
+ return 1f; // Default fallback
+ }
+
+ // Read from ProjectileConfig settings - same source as ProjectileBase.Initialize()
+ return _currentAmmo.mass;
+ }
+
#endregion
#region Projectile Management
@@ -173,7 +169,7 @@ namespace Minigames.FortFight.Core
// Lock trajectory to show the shot path
if (trajectoryPreview != null)
{
- float lockDuration = CachedSettings?.TrajectoryLockDuration ?? 2f;
+ float lockDuration = Config?.trajectoryLockDuration ?? 2f;
trajectoryPreview.LockTrajectory(lockDuration);
}
diff --git a/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs b/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs
deleted file mode 100644
index 264d7690..00000000
--- a/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-using Core;
-using UnityEngine;
-
-namespace Minigames.FortFight.Core
-{
- ///
- /// Displays trajectory prediction line for projectile launches.
- /// Shows dotted line preview of projectile arc.
- ///
- [RequireComponent(typeof(LineRenderer))]
- public class TrajectoryPreview : MonoBehaviour
- {
- [Header("Trajectory Settings")]
- [Tooltip("Number of points to simulate (physics steps)")]
- [SerializeField] private int simulationSteps = 50;
-
- [Header("Visual")]
- [Tooltip("Color of trajectory line")]
- [SerializeField] private Color lineColor = Color.yellow;
-
- [Tooltip("Width of trajectory line")]
- [SerializeField] private float lineWidth = 0.1f;
-
- private LineRenderer lineRenderer;
- private bool isLocked = false;
- private float lockTimer = 0f;
- private float lockDuration = 0f;
-
- private void Awake()
- {
- lineRenderer = GetComponent();
-
- // Configure line renderer
- if (lineRenderer != null)
- {
- lineRenderer.startWidth = lineWidth;
- lineRenderer.endWidth = lineWidth;
- lineRenderer.startColor = lineColor;
- lineRenderer.endColor = lineColor;
- lineRenderer.positionCount = simulationSteps;
- lineRenderer.enabled = false;
- }
- }
-
- private void Update()
- {
- if (isLocked)
- {
- lockTimer += Time.deltaTime;
- if (lockTimer >= lockDuration)
- {
- isLocked = false;
- Hide();
- }
- }
- }
-
- ///
- /// Show the trajectory preview
- ///
- public void Show()
- {
- if (lineRenderer != null)
- {
- lineRenderer.enabled = true;
- }
- }
-
- ///
- /// Hide the trajectory preview (unless locked)
- ///
- public void Hide()
- {
- // Don't hide if trajectory is locked
- if (isLocked)
- return;
-
- if (lineRenderer != null)
- {
- lineRenderer.enabled = false;
- }
- }
-
- ///
- /// Lock the current trajectory display for a duration
- ///
- public void LockTrajectory(float duration)
- {
- isLocked = true;
- lockTimer = 0f;
- lockDuration = duration;
-
- // Ensure line is visible
- if (lineRenderer != null)
- {
- lineRenderer.enabled = true;
- }
- }
-
- ///
- /// Update the trajectory preview with new parameters.
- /// Uses Physics.fixedDeltaTime for accurate simulation matching Unity's physics.
- ///
- /// Starting position of trajectory
- /// Launch direction (normalized)
- /// Launch force (impulse)
- /// Projectile mass
- public void UpdateTrajectory(Vector2 startPosition, Vector2 direction, float force, float mass = 1f)
- {
- if (lineRenderer == null) return;
-
- // Calculate initial velocity: impulse force F gives velocity v = F/m
- Vector2 startVelocity = (direction * force) / mass;
-
- // Get gravity with projectile gravity scale from settings
- var settings = GameManager.GetSettingsObject();
- float gravityScale = settings?.ProjectileGravityScale ?? 1f;
- Vector2 gravity = new Vector2(Physics2D.gravity.x, Physics2D.gravity.y) * gravityScale;
-
- // Simulate trajectory using Unity's physics time step
- Vector3[] points = new Vector3[simulationSteps];
- Vector2 pos = startPosition;
- Vector2 vel = startVelocity;
-
- for (int i = 0; i < simulationSteps; i++)
- {
- // Set current position
- points[i] = new Vector3(pos.x, pos.y, 0);
-
- // Update velocity (gravity applied over fixedDeltaTime)
- vel = vel + gravity * Time.fixedDeltaTime;
-
- // Update position (velocity applied over fixedDeltaTime)
- pos = pos + vel * Time.fixedDeltaTime;
-
- // Optional: Stop if hits ground (y < threshold)
- if (pos.y < -10f)
- {
- // Fill remaining points at ground level
- for (int j = i + 1; j < simulationSteps; j++)
- {
- points[j] = new Vector3(pos.x, -10f, 0);
- }
- break;
- }
- }
-
- lineRenderer.positionCount = simulationSteps;
- lineRenderer.SetPositions(points);
- }
- }
-}
-
diff --git a/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs.meta b/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs.meta
deleted file mode 100644
index 453a7a47..00000000
--- a/Assets/Scripts/Minigames/FortFight/Core/TrajectoryPreview.cs.meta
+++ /dev/null
@@ -1,3 +0,0 @@
-fileFormatVersion: 2
-guid: b1e26667c6d4415f8dc51e4a58ba9479
-timeCreated: 1764682615
\ No newline at end of file
diff --git a/Assets/Settings/FortFightSettings.asset b/Assets/Settings/FortFightSettings.asset
index dd3e15f9..18ca7579 100644
--- a/Assets/Settings/FortFightSettings.asset
+++ b/Assets/Settings/FortFightSettings.asset
@@ -13,15 +13,13 @@ MonoBehaviour:
m_Name: FortFightSettings
m_EditorClassIdentifier: AppleHillsScripts::Minigames.FortFight.Core.FortFightSettings
slingshotSettings:
- maxDragDistance: 5
+ maxDragDistance: 10
baseLaunchForce: 125
minForceMultiplier: 0.1
maxForceMultiplier: 1
trajectoryPoints: 50
trajectoryTimeStep: 0.1
trajectoryLockDuration: 2
- gravity: 9.81
- defaultProjectileMass: 1
autoRegisterInput: 0
materialConfigs:
- material: 0
@@ -119,10 +117,6 @@ MonoBehaviour:
ceilingFanActivationDelay: 1
ceilingFanDropDelay: 0.2
ceilingFanDropSpeed: 20
- baseLaunchForce: 150
- minForceMultiplier: 0.1
- maxForceMultiplier: 1
- trajectoryLockDuration: 2
fortBlockLayer: 16
projectileLayer: 15
damageColorTint: {r: 1, g: 0, b: 0, a: 1}