Gondwana Game Engine Development (master) - 2.6.1
Gondwana is a cross-platform 2.5D game and rendering engine written in C#/.NET 8. It provides fine-grained control over rendering, timing, and scene composition, with built-in support for parallax, z-ordering, pixel overhang, collision detection, and particle effects. Gondwana targets desktop and web platforms using SkiaSharp for graphics and pluggable audio backends for desktop and browser targets.
Loading...
Searching...
No Matches
Sprite.Jiggle.cs
1using System.Drawing;
2
4
8public partial class Sprite
9{
10 // ------------------------------------------------------------
11 // Jiggle configuration/state
12 // ------------------------------------------------------------
13
14 private bool _isJiggling;
15 private float _jiggleElapsedSeconds;
16 private double _jiggleAccumulatedSeconds;
17
18 private float _jiggleIntensityX;
19 private float _jiggleIntensityY;
20 private float _jiggleSpeed;
21 private float _jiggleScaleIntensity;
22 private bool _jiggleAffectsScale;
23 private bool _jiggleLoop;
24 private float _jiggleDurationSeconds; // ignored if loop = true
25
26 // Per-sprite phase offsets so multiple sprites do not move in sync
27 private float _jigglePhaseX1;
28 private float _jigglePhaseX2;
29 private float _jigglePhaseY1;
30 private float _jigglePhaseY2;
31 private float _jigglePhaseScale;
32
33 // Current computed visual offsets
34 private float _prevJiggleOffsetX;
35 private float _prevJiggleOffsetY;
36 private float _jiggleOffsetX;
37 private float _jiggleOffsetY;
38 private float _jiggleScale = 1f;
39
40 // Optional decay support
41 private bool _jiggleDecay;
42 private float _jiggleStartIntensityX;
43 private float _jiggleStartIntensityY;
44 private float _jiggleStartScaleIntensity;
45
49 public bool IsJiggling => _isJiggling;
50
55 public PointF JiggleOffset => new(_jiggleOffsetX, _jiggleOffsetY);
56
61 public float JiggleScale => _jiggleScale;
62
84 public void StartJiggle(
85 float intensityX = 2f,
86 float intensityY = 2f,
87 float speed = 8f,
88 float durationSeconds = 0.25f,
89 bool loop = false,
90 bool affectsScale = false,
91 float scaleIntensity = 0.02f,
92 bool decay = true)
93 {
94 _isJiggling = true;
95 _jiggleElapsedSeconds = 0f;
96
97 _jiggleIntensityX = MathF.Max(0f, intensityX);
98 _jiggleIntensityY = MathF.Max(0f, intensityY);
99 _jiggleSpeed = MathF.Max(0f, speed);
100 _jiggleScaleIntensity = MathF.Max(0f, scaleIntensity);
101 _jiggleAffectsScale = affectsScale;
102 _jiggleLoop = loop;
103 _jiggleDurationSeconds = MathF.Max(0f, durationSeconds);
104
105 _jiggleDecay = decay;
106 _jiggleStartIntensityX = _jiggleIntensityX;
107 _jiggleStartIntensityY = _jiggleIntensityY;
108 _jiggleStartScaleIntensity = _jiggleScaleIntensity;
109
110 // Randomize phases so identical sprites do not move in lockstep
111 _jigglePhaseX1 = Random.Shared.NextSingle() * MathF.PI * 2f;
112 _jigglePhaseX2 = Random.Shared.NextSingle() * MathF.PI * 2f;
113 _jigglePhaseY1 = Random.Shared.NextSingle() * MathF.PI * 2f;
114 _jigglePhaseY2 = Random.Shared.NextSingle() * MathF.PI * 2f;
115 _jigglePhaseScale = Random.Shared.NextSingle() * MathF.PI * 2f;
116
117 _jiggleOffsetX = 0f;
118 _jiggleOffsetY = 0f;
119 _jiggleScale = 1f;
120 }
121
125 public void StopJiggle()
126 {
127 _isJiggling = false;
128 _prevJiggleOffsetX = 0f;
129 _prevJiggleOffsetY = 0f;
130 _jiggleOffsetX = 0f;
131 _jiggleOffsetY = 0f;
132 _jiggleScale = 1f;
133 }
134
141 internal void AdvanceJiggle(float deltaSeconds)
142 {
143 if (!_isJiggling)
144 return;
145
146 // Determine target update rate
147 int targetFps = Engine.Instance.Configuration.TargetFPS;
148 float step = (targetFps > 0) ? (1f / targetFps) : deltaSeconds; // if uncapped, just run
149
150 _jiggleAccumulatedSeconds += deltaSeconds;
151
152 // Only advance at most once per "frame step"
153 if (_jiggleAccumulatedSeconds < step)
154 return;
155
156 // Consume one step (don’t loop; keep it cheap and stable)
157 float dt = step;
158 _jiggleAccumulatedSeconds -= step;
159
160 _prevJiggleOffsetX = _jiggleOffsetX;
161 _prevJiggleOffsetY = _jiggleOffsetY;
162
163 _jiggleElapsedSeconds += dt;
164
165 if (!_jiggleLoop && _jiggleDurationSeconds > 0f && _jiggleElapsedSeconds >= _jiggleDurationSeconds)
166 {
167 StopJiggle();
168 return;
169 }
170
171 float intensityX = _jiggleIntensityX;
172 float intensityY = _jiggleIntensityY;
173 float scaleIntensity = _jiggleScaleIntensity;
174
175 if (_jiggleDecay && !_jiggleLoop && _jiggleDurationSeconds > 0f)
176 {
177 float lifeT = _jiggleElapsedSeconds / _jiggleDurationSeconds;
178 lifeT = Math.Clamp(lifeT, 0f, 1f);
179
180 float decayFactor = 1f - lifeT;
181
182 intensityX = _jiggleStartIntensityX * decayFactor;
183 intensityY = _jiggleStartIntensityY * decayFactor;
184 scaleIntensity = _jiggleStartScaleIntensity * decayFactor;
185 }
186
187 float t = _jiggleElapsedSeconds * _jiggleSpeed;
188
189 float xWave =
190 MathF.Sin(t + _jigglePhaseX1) +
191 (0.5f * MathF.Sin((t * 2.37f) + _jigglePhaseX2));
192
193 float yWave =
194 MathF.Cos((t * 1.13f) + _jigglePhaseY1) +
195 (0.5f * MathF.Cos((t * 2.91f) + _jigglePhaseY2));
196
197 _jiggleOffsetX = xWave * 0.6667f * intensityX;
198 _jiggleOffsetY = yWave * 0.6667f * intensityY;
199
200 if (_jiggleAffectsScale && scaleIntensity > 0f)
201 {
202 float scaleWave =
203 MathF.Sin((t * 1.41f) + _jigglePhaseScale) +
204 (0.35f * MathF.Sin((t * 3.17f) + (_jigglePhaseScale * 0.5f)));
205
206 _jiggleScale = 1f + (scaleWave * 0.7407f * scaleIntensity);
207 if (_jiggleScale < 0.01f)
208 _jiggleScale = 0.01f;
209 }
210 else
211 {
212 _jiggleScale = 1f;
213 }
214
215 bool changed =
216 Math.Abs(_jiggleOffsetX - _prevJiggleOffsetX) > 0.01f ||
217 Math.Abs(_jiggleOffsetY - _prevJiggleOffsetY) > 0.01f;
218
219 if (changed && _sceneLayer != null)
220 {
221 var rect = DrawLocationWorld;
222
223 int inflateX = (int)MathF.Ceiling(_jiggleIntensityX);
224 int inflateY = (int)MathF.Ceiling(_jiggleIntensityY);
225
226 rect.Inflate(inflateX, inflateY);
227
228 _sceneLayer.RefreshQueue.AddWorldRect(rect);
229 }
230 }
231
238 internal RectangleF ApplyJiggleToDestRect(RectangleF destRect)
239 {
240 if (!_isJiggling)
241 return destRect;
242
243 RectangleF result = destRect;
244 result.Offset(_jiggleOffsetX, _jiggleOffsetY);
245
246 if (Math.Abs(_jiggleScale - 1f) > 0.0001f)
247 {
248 float centerX = result.X + (result.Width / 2f);
249 float centerY = result.Y + (result.Height / 2f);
250
251 result.Width *= _jiggleScale;
252 result.Height *= _jiggleScale;
253 result.X = centerX - (result.Width / 2f);
254 result.Y = centerY - (result.Height / 2f);
255 }
256
257 return result;
258 }
259
270 public void JiggleOnce(
271 float intensityX = 2f,
272 float intensityY = 2f,
273 float speed = 12f,
274 float durationSeconds = 0.18f,
275 bool affectsScale = false,
276 float scaleIntensity = 0.015f)
277 {
279 intensityX: intensityX,
280 intensityY: intensityY,
281 speed: speed,
282 durationSeconds: durationSeconds,
283 loop: false,
284 affectsScale: affectsScale,
285 scaleIntensity: scaleIntensity,
286 decay: true);
287 }
288}
Represents a movable visual element on a scene layer.
Definition Sprite.cs:20
override Rectangle DrawLocationWorld
Definition Sprite.cs:579
void StopJiggle()
Stops the current jiggle effect.
void StartJiggle(float intensityX=2f, float intensityY=2f, float speed=8f, float durationSeconds=0.25f, bool loop=false, bool affectsScale=false, float scaleIntensity=0.02f, bool decay=true)
Starts a smooth, randomized-looking jiggle animation. This jiggle is visual only and does not modify ...
PointF JiggleOffset
Gets the current visual jiggle offset in screen/world pixels, depending on how the sprite is being dr...
bool IsJiggling
Gets whether the sprite is currently jiggling.
float JiggleScale
Gets the current visual jiggle scale multiplier. This is intended to be applied at draw time only.
void JiggleOnce(float intensityX=2f, float intensityY=2f, float speed=12f, float durationSeconds=0.18f, bool affectsScale=false, float scaleIntensity=0.015f)
Starts a one-shot impact-style jiggle. Handy for hits, invalid selections, bump feedback,...
Represents the core game engine singleton responsible for managing the main update loop,...
Definition Engine.cs:36
static Engine Instance
Gets the singleton instance of the Engine.
Definition Engine.cs:49
EngineConfiguration Configuration
Gets the current engine configuration settings.
Definition Engine.cs:928