Skip to content

Commit bc7d867

Browse files
authored
Update ProjectileVisual_.cs
1 parent 0cd667e commit bc7d867

1 file changed

Lines changed: 56 additions & 133 deletions

File tree

Lines changed: 56 additions & 133 deletions
Original file line numberDiff line numberDiff line change
@@ -1,129 +1,87 @@
1-
// ProjectileVisual_.cs
1+
// ProjectileVisual_.cs — 2D pool visual
22
//
3-
// FIX (rotation): InitializeClientVisual now uses angle-based Z rotation for
4-
// 2D visuals (dir.z ≈ 0) instead of LookRotation(forward, dir).
5-
// LookRotation interprets the second argument as the UP vector, which
6-
// rotated the sprite 90° incorrectly for horizontal bullets.
7-
// For 3D visuals (non-zero Z component), LookRotation(dir) is used.
3+
// Inherits ProjectileVisualBase.
4+
// Handles: SpriteRenderer, TrailRenderer, 2D Z-axis rotation.
85
//
9-
// FIX (draw order): SpriteRenderer.sortingOrder = 1, TrailRenderer.sortingOrder = 0.
10-
// The sprite now renders in front of the trail within the same sorting layer.
11-
// Adjust these values in the inspector if you have multiple sorting layers.
12-
//
13-
// FIX (trail bug): ApplyTrailOptimised condition was checking
14-
// "_cachedConfigId != _cachedConfigId" (always false). Fixed to check
15-
// the _trailConfigured flag which is reset on pool return and config change.
6+
// FIXES carried forward:
7+
// + Correct 2D rotation via atan2 → Z-Euler (not LookRotation)
8+
// + _trailConfigured flag properly gates re-application on recycled objects
9+
// + SpriteRenderer.sortingOrder > TrailRenderer.sortingOrder
1610

1711
using UnityEngine;
18-
using MidManStudio.Core.Logging;
19-
using MidManStudio.Core.Pools;
2012
using MidManStudio.Projectiles.Config;
2113

2214
namespace MidManStudio.Projectiles.Visuals
2315
{
24-
public class ProjectileVisual_ : MonoBehaviour
16+
public class ProjectileVisual_ : ProjectileVisualBase
2517
{
26-
#region Serialized Fields
18+
#region Inspector
2719

28-
[Header("Renderers")]
29-
[SerializeField] public SpriteRenderer projectileSpriteRend;
30-
[SerializeField] public TrailRenderer projectileTrailRend;
20+
[Header("2D Renderers")]
21+
[SerializeField] public SpriteRenderer projectileSpriteRend;
22+
[SerializeField] public TrailRenderer projectileTrailRend;
3123

3224
[Header("Draw Order")]
33-
[Tooltip("Sorting order for the sprite renderer. Higher = in front.")]
3425
[SerializeField] private int _spriteSortingOrder = 1;
35-
[Tooltip("Sorting order for the trail renderer. Should be lower than sprite.")]
3626
[SerializeField] private int _trailSortingOrder = 0;
3727

38-
[Header("Pool Return")]
39-
[SerializeField] private LocalPoolReturn localPoolReturn;
40-
41-
[Header("Debug")]
42-
[SerializeField] private MID_LogLevel _logLevel = MID_LogLevel.None;
43-
4428
#endregion
4529

46-
#region Cached State
30+
#region State
4731

48-
private ProjectileConfigSO _config;
49-
private Sprite _cachedSprite;
50-
private bool _trailConfigured;
51-
private ushort _cachedConfigId;
52-
private bool _initialised;
32+
private Sprite _cachedSprite;
33+
private bool _trailConfigured;
34+
private ushort _cachedConfigId;
35+
private bool _configInitialised;
5336

5437
#endregion
5538

56-
private void Awake()
39+
#region ProjectileVisualBase
40+
41+
protected override void ApplyRotation(Vector3 dir)
5742
{
58-
if (localPoolReturn == null)
59-
localPoolReturn = GetComponent<LocalPoolReturn>();
43+
// 2D: rotate around Z so the sprite tip points along dir
44+
if (dir.sqrMagnitude < 0.001f) return;
45+
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
46+
transform.rotation = Quaternion.Euler(0f, 0f, angle);
6047
}
6148

62-
#region Public API
63-
64-
public void InitializeClientVisual(
65-
ushort configId,
66-
Vector3 origin,
67-
Vector3 direction,
68-
float speed)
49+
protected override void OnInitialise(ProjectileConfigSO cfg)
6950
{
70-
if (localPoolReturn == null)
71-
localPoolReturn = GetComponent<LocalPoolReturn>();
72-
73-
bool configChanged = !_initialised || _cachedConfigId != configId;
74-
51+
bool configChanged = !_configInitialised || _cachedConfigId != ConfigId;
7552
if (configChanged)
7653
{
77-
_config = ProjectileRegistry.HasInstance
78-
? ProjectileRegistry.Instance.Get(configId)
79-
: null;
80-
81-
_cachedConfigId = configId;
82-
_trailConfigured = false;
54+
_cachedConfigId = ConfigId;
55+
_trailConfigured = false;
56+
_configInitialised = true;
8357
}
8458

85-
if (_config == null)
86-
MID_Logger.LogWarning(_logLevel,
87-
$"ProjectileVisual_: no config for id={configId}.",
88-
nameof(ProjectileVisual_));
59+
ApplySpriteOptimised(cfg?.ProjectileSprite);
60+
ApplyTrailOptimised(cfg);
61+
}
8962

90-
transform.position = origin;
63+
protected override void OnReturnToPool()
64+
{
65+
_configInitialised = false;
66+
_trailConfigured = false;
67+
_cachedSprite = null;
9168

92-
// FIX: correct 2D/3D rotation
93-
if (direction.sqrMagnitude > 0.001f)
69+
if (projectileSpriteRend != null)
9470
{
95-
if (Mathf.Abs(direction.z) < 0.01f)
96-
{
97-
// 2D projectile — rotate around Z axis
98-
float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
99-
transform.rotation = Quaternion.Euler(0f, 0f, angle);
100-
}
101-
else
102-
{
103-
// 3D projectile — align forward to travel direction
104-
transform.rotation = Quaternion.LookRotation(direction.normalized);
105-
}
71+
projectileSpriteRend.enabled = true;
72+
projectileSpriteRend.sprite = null;
73+
projectileSpriteRend.color = Color.white;
10674
}
10775

108-
ApplySpriteOptimised(_config?.ProjectileSprite);
109-
ApplyTrailOptimised(_config);
110-
111-
_initialised = true;
112-
113-
MID_Logger.LogDebug(_logLevel,
114-
$"Initialised configId={configId} origin={origin}",
115-
nameof(ProjectileVisual_));
116-
}
117-
118-
public void ReturnToPoolImmediate()
119-
{
120-
if (this == null) return;
121-
CleanupForPoolReturn();
122-
if (localPoolReturn != null)
123-
localPoolReturn.ReturnToPoolNow();
76+
if (projectileTrailRend != null)
77+
{
78+
projectileTrailRend.emitting = false;
79+
projectileTrailRend.enabled = false;
80+
projectileTrailRend.Clear();
81+
}
12482
}
12583

126-
public void HideProjectile()
84+
public override void HideProjectile()
12785
{
12886
if (projectileSpriteRend != null) projectileSpriteRend.enabled = false;
12987
if (projectileTrailRend != null) projectileTrailRend.emitting = false;
@@ -136,14 +94,11 @@ public void HideProjectile()
13694
private void ApplySpriteOptimised(Sprite sprite)
13795
{
13896
if (projectileSpriteRend == null) return;
139-
14097
bool shouldShow = sprite != null;
141-
projectileSpriteRend.enabled = shouldShow;
142-
// FIX: sprite draws in front of trail
143-
projectileSpriteRend.sortingOrder = _spriteSortingOrder;
98+
projectileSpriteRend.enabled = shouldShow;
99+
projectileSpriteRend.sortingOrder = _spriteSortingOrder;
144100

145101
if (!shouldShow) return;
146-
147102
if (_cachedSprite != sprite)
148103
{
149104
projectileSpriteRend.sprite = sprite;
@@ -163,7 +118,6 @@ private void ApplyTrailOptimised(ProjectileConfigSO cfg)
163118
return;
164119
}
165120

166-
// FIX: _trailConfigured flag correctly gates re-application on recycled objects
167121
if (!_trailConfigured)
168122
{
169123
if (cfg.TrailMaterial != null)
@@ -177,20 +131,18 @@ private void ApplyTrailOptimised(ProjectileConfigSO cfg)
177131
if (cfg.UseGradientOverride && cfg.TrailGradient != null)
178132
projectileTrailRend.colorGradient = cfg.TrailGradient;
179133

180-
projectileTrailRend.time = cfg.TrailTime;
181-
projectileTrailRend.startWidth = cfg.TrailStartWidth;
182-
projectileTrailRend.endWidth = cfg.TrailEndWidth;
183-
projectileTrailRend.numCapVertices = cfg.TrailCapVertices;
184-
projectileTrailRend.minVertexDistance = cfg.TrailMinVertexDistance;
134+
projectileTrailRend.time = cfg.TrailTime;
135+
projectileTrailRend.startWidth = cfg.TrailStartWidth;
136+
projectileTrailRend.endWidth = cfg.TrailEndWidth;
137+
projectileTrailRend.numCapVertices = cfg.TrailCapVertices;
138+
projectileTrailRend.minVertexDistance = cfg.TrailMinVertexDistance;
185139

186140
projectileTrailRend.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
187141
projectileTrailRend.receiveShadows = false;
188142
projectileTrailRend.generateLightingData = false;
189143
projectileTrailRend.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
190144
projectileTrailRend.alignment = LineAlignment.View;
191-
192-
// FIX: trail behind sprite
193-
projectileTrailRend.sortingOrder = _trailSortingOrder;
145+
projectileTrailRend.sortingOrder = _trailSortingOrder;
194146

195147
_trailConfigured = true;
196148
}
@@ -201,34 +153,5 @@ private void ApplyTrailOptimised(ProjectileConfigSO cfg)
201153
}
202154

203155
#endregion
204-
205-
#region Pool Cleanup
206-
207-
private void CleanupForPoolReturn()
208-
{
209-
_initialised = false;
210-
_config = null;
211-
_trailConfigured = false;
212-
_cachedSprite = null;
213-
214-
if (projectileSpriteRend != null)
215-
{
216-
projectileSpriteRend.enabled = true;
217-
projectileSpriteRend.sprite = null;
218-
projectileSpriteRend.color = Color.white;
219-
}
220-
221-
if (projectileTrailRend != null)
222-
{
223-
projectileTrailRend.emitting = false;
224-
projectileTrailRend.enabled = false;
225-
projectileTrailRend.Clear();
226-
}
227-
228-
MID_Logger.LogDebug(_logLevel, "Cleaned up for pool return.",
229-
nameof(ProjectileVisual_));
230-
}
231-
232-
#endregion
233156
}
234157
}

0 commit comments

Comments
 (0)