Skip to content

Commit cf2b4a0

Browse files
committed
0.7.0: overhaul explosion lighting, material logic, and wave physics
- refactor(visuals): split particles into Lit (debris/dust) and Unlit (fire/sparks) so inert matter respects 2D lighting and shadows - fix(materials): replace localized name-matching with internal `hitsound`/`stepsound` classification for 100% language-independent block support - feat(physics): implement full column scanning to eject debris from all exposed faces (walls, ceilings, overhangs) instead of just top surfaces - feat(physics): add realistic wave propagation delay and open-air pressure wave dust ("Airwave") - fix(spawning): alternate center-outward scan priority to guarantee perfect left/right explosion symmetry - fix(spawning): correctly block bottom 3 sectors for ground mines to enforce a symmetric upward blast cone - perf(core): use pre-allocated buffers in hot paths to eliminate GC stutters (fixes ~0.05s frame drops) - feat(config): add `BlockDebrisCountMultiplier` to allow user performance tuning
1 parent 7bba08b commit cf2b4a0

12 files changed

Lines changed: 1500 additions & 938 deletions

Core/ShrapnelFactory.cs

Lines changed: 47 additions & 132 deletions
Large diffs are not rendered by default.

Effects/BulletImpactEffects.cs

Lines changed: 85 additions & 145 deletions
Large diffs are not rendered by default.

Effects/ExplosionEffectsLogic.cs

Lines changed: 120 additions & 205 deletions
Large diffs are not rendered by default.

Effects/GroundDebrisLogic.cs

Lines changed: 323 additions & 206 deletions
Large diffs are not rendered by default.

Helpers/BlockClassifier.cs

Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
using UnityEngine;
2+
3+
namespace ScavShrapnelMod.Helpers
4+
{
5+
/// <summary>
6+
/// Material category for blocks.
7+
/// Classified from internal game data (hitsound, stepsound, metallic flag).
8+
/// Never from block name (localized, unreliable).
9+
/// </summary>
10+
public enum MaterialCategory
11+
{
12+
Unknown,
13+
Sand, // hitsound=sand, stepsound=Sand
14+
Snow, // hitsound=sand, stepsound=Snow
15+
Dirt, // hitsound=dirt
16+
Rock, // hitsound=rock
17+
Concrete, // hitsound=concrete
18+
Metal, // metallic=true OR hitsound=steel/scrapmetal
19+
Wood, // hitsound=wood
20+
Glass, // hitsound=glass, stepsound=Glass
21+
Ice, // hitsound=glass, stepsound=Ice
22+
Rubber, // hitsound=rubber, stepsound=Rubber
23+
Plastic, // hitsound=rubber, stepsound=Plastic
24+
Organic, // hitsound=rustle or gore2
25+
Trash, // hitsound=trash
26+
Ore // hitsound=crystal
27+
}
28+
29+
/// <summary>
30+
/// Centralized block material classification system.
31+
/// Uses internal game data only — never localized block names.
32+
///
33+
/// Shared by:
34+
/// - GroundDebrisLogic (ground surface particles)
35+
/// - ShrapnelSpawnLogic (block debris from destroyed blocks)
36+
/// - Any future systems needing material-aware logic
37+
///
38+
/// Based on GetBlockInfo() switch statement (35 block types).
39+
/// 100% coverage via hitsound/stepsound mapping.
40+
/// </summary>
41+
public static class BlockClassifier
42+
{
43+
/// <summary>
44+
/// Classifies a block into a material category.
45+
/// Priority: metallic flag → hitsound → stepsound refinement.
46+
/// </summary>
47+
/// <param name="info">BlockInfo from WorldGeneration.GetBlockInfo(). Null-safe.</param>
48+
/// <returns>MaterialCategory enum value.</returns>
49+
public static MaterialCategory Classify(BlockInfo info)
50+
{
51+
if (info == null) return MaterialCategory.Unknown;
52+
if (info.metallic) return MaterialCategory.Metal;
53+
54+
string hit = info.hitsound ?? string.Empty;
55+
string step = info.stepsound ?? string.Empty;
56+
57+
// WHY: hitsound is the primary material indicator.
58+
// stepsound refines ambiguous cases (sand vs snow, glass vs ice).
59+
60+
if (hit == "steel" || hit == "scrapmetal") return MaterialCategory.Metal;
61+
if (hit == "rock") return MaterialCategory.Rock;
62+
if (hit == "sand") return (step == "Snow") ? MaterialCategory.Snow : MaterialCategory.Sand;
63+
if (hit == "dirt") return MaterialCategory.Dirt;
64+
if (hit == "wood") return MaterialCategory.Wood;
65+
if (hit == "concrete") return MaterialCategory.Concrete;
66+
if (hit == "glass") return (step == "Ice") ? MaterialCategory.Ice : MaterialCategory.Glass;
67+
if (hit == "rubber") return (step == "Plastic") ? MaterialCategory.Plastic : MaterialCategory.Rubber;
68+
if (hit == "rustle") return MaterialCategory.Organic;
69+
if (hit == "gore2") return MaterialCategory.Organic;
70+
if (hit == "trash") return MaterialCategory.Trash;
71+
if (hit == "crystal") return MaterialCategory.Ore;
72+
73+
return MaterialCategory.Unknown;
74+
}
75+
76+
/// <summary>
77+
/// Returns dust count multiplier for a material category.
78+
/// Soft/loose materials produce more fine dust.
79+
/// Hard/dense materials produce fewer, larger chunks.
80+
/// Range: 0.8 – 1.3 (max 1.6× difference).
81+
/// </summary>
82+
public static float GetDustMultiplier(MaterialCategory cat)
83+
{
84+
switch (cat)
85+
{
86+
case MaterialCategory.Sand: return 1.3f;
87+
case MaterialCategory.Snow: return 1.25f;
88+
case MaterialCategory.Dirt: return 1.2f;
89+
case MaterialCategory.Organic: return 1.15f;
90+
case MaterialCategory.Trash: return 1.1f;
91+
case MaterialCategory.Glass: return 1.1f;
92+
case MaterialCategory.Ice: return 1.1f;
93+
case MaterialCategory.Wood: return 1.05f;
94+
case MaterialCategory.Plastic: return 1.0f;
95+
case MaterialCategory.Rubber: return 0.95f;
96+
case MaterialCategory.Rock: return 0.9f;
97+
case MaterialCategory.Concrete: return 0.9f;
98+
case MaterialCategory.Ore: return 0.85f;
99+
case MaterialCategory.Metal: return 0.8f;
100+
default: return 1.0f;
101+
}
102+
}
103+
104+
/// <summary>
105+
/// Returns base color for a material category.
106+
/// Randomized within each category's palette.
107+
/// Used for ground debris and block destruction particles.
108+
/// </summary>
109+
public static Color GetColor(MaterialCategory cat, System.Random rng)
110+
{
111+
switch (cat)
112+
{
113+
case MaterialCategory.Sand:
114+
// Warm yellow-tan
115+
return new Color(
116+
rng.Range(0.72f, 0.86f),
117+
rng.Range(0.62f, 0.76f),
118+
rng.Range(0.32f, 0.46f));
119+
120+
case MaterialCategory.Snow:
121+
// White with slight blue tint
122+
{
123+
float w = rng.Range(0.85f, 0.97f);
124+
return new Color(w * 0.98f, w, w * 1.02f);
125+
}
126+
127+
case MaterialCategory.Dirt:
128+
// Dark earthy brown
129+
return new Color(
130+
rng.Range(0.38f, 0.52f),
131+
rng.Range(0.25f, 0.38f),
132+
rng.Range(0.12f, 0.22f));
133+
134+
case MaterialCategory.Rock:
135+
// Neutral gray with slight warm tint
136+
{
137+
float g = rng.Range(0.38f, 0.56f);
138+
return new Color(g, g * 0.97f, g * 0.93f);
139+
}
140+
141+
case MaterialCategory.Concrete:
142+
// Light gray, slightly warmer than rock
143+
{
144+
float g = rng.Range(0.45f, 0.6f);
145+
return new Color(g * 1.02f, g, g * 0.96f);
146+
}
147+
148+
case MaterialCategory.Metal:
149+
// Cool blue-gray (steel/alloy tint)
150+
{
151+
float g = rng.Range(0.28f, 0.44f);
152+
return new Color(g * 0.92f, g * 0.96f, g * 1.1f);
153+
}
154+
155+
case MaterialCategory.Wood:
156+
// Warm medium brown
157+
return new Color(
158+
rng.Range(0.42f, 0.56f),
159+
rng.Range(0.26f, 0.38f),
160+
rng.Range(0.12f, 0.2f));
161+
162+
case MaterialCategory.Glass:
163+
// Light blue-white (transparent debris)
164+
{
165+
float g = rng.Range(0.6f, 0.78f);
166+
return new Color(g * 0.92f, g * 0.97f, g * 1.05f);
167+
}
168+
169+
case MaterialCategory.Ice:
170+
// Pale blue (colder than glass)
171+
{
172+
float g = rng.Range(0.65f, 0.82f);
173+
return new Color(g * 0.88f, g * 0.95f, g * 1.08f);
174+
}
175+
176+
case MaterialCategory.Rubber:
177+
// Very dark gray (tire-black)
178+
{
179+
float g = rng.Range(0.12f, 0.22f);
180+
return new Color(g, g, g);
181+
}
182+
183+
case MaterialCategory.Plastic:
184+
// Light off-white gray
185+
{
186+
float g = rng.Range(0.55f, 0.72f);
187+
return new Color(g * 1.01f, g, g * 0.97f);
188+
}
189+
190+
case MaterialCategory.Organic:
191+
// Green-brown (plant/fungal)
192+
return new Color(
193+
rng.Range(0.22f, 0.38f),
194+
rng.Range(0.32f, 0.48f),
195+
rng.Range(0.12f, 0.25f));
196+
197+
case MaterialCategory.Trash:
198+
// Dark mixed gray-brown
199+
{
200+
float g = rng.Range(0.2f, 0.35f);
201+
return new Color(g * 1.1f, g * 0.95f, g * 0.85f);
202+
}
203+
204+
case MaterialCategory.Ore:
205+
// Copper-tinted (warm metallic)
206+
{
207+
float g = rng.Range(0.35f, 0.5f);
208+
return new Color(g * 1.25f, g * 0.85f, g * 0.55f);
209+
}
210+
211+
default:
212+
// Unknown: safe neutral gray
213+
{
214+
float g = rng.Range(0.35f, 0.5f);
215+
return new Color(g, g * 0.98f, g * 0.95f);
216+
}
217+
}
218+
}
219+
220+
/// <summary>
221+
/// Returns color with specified alpha.
222+
/// Convenience wrapper for debris particles.
223+
/// </summary>
224+
public static Color GetColorWithAlpha(MaterialCategory cat, System.Random rng, float alpha)
225+
{
226+
Color c = GetColor(cat, rng);
227+
c.a = alpha;
228+
return c;
229+
}
230+
}
231+
}

0 commit comments

Comments
 (0)