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
FrameSequence.cs
1using System.Collections;
2using System.Runtime.Serialization;
4using Newtonsoft.Json;
5
7
11public struct FrameSequence : IEnumerable<Frame>
12{
13 #region fields
14
18 [JsonProperty]
20
21 [JsonProperty]
22 private List<Frame> frameList;
23
24 [JsonProperty]
25 private List<double?>? frameDurations;
26
30 public double? GetDurationSeconds(int index) =>
31 frameDurations is not null && index < frameDurations.Count ? frameDurations[index] : null;
32
36 public void SetDurationSeconds(int index, double? seconds)
37 {
38 if (index < 0 || index >= FrameCount) throw new ArgumentOutOfRangeException(nameof(index));
39 if (seconds is { } duration && (!double.IsFinite(duration) || duration <= 0))
40 throw new ArgumentOutOfRangeException(nameof(seconds));
41 // Copy on write: cloned cycles share images, but editing timing must not change the original.
42 frameDurations = frameDurations is null ? new List<double?>() : new(frameDurations);
43 while (frameDurations.Count < FrameCount) frameDurations.Add(null);
44 frameDurations[index] = seconds;
45 }
46
47 internal void SetDurations(IEnumerable<double?> durations)
48 {
49 var values = durations.ToList();
50 if (values.Count != FrameCount || values.Any(v => v is { } d && (!double.IsFinite(d) || d <= 0)))
51 throw new ArgumentException("Durations must match the sequence and be positive finite values or null.", nameof(durations));
52 frameDurations = values.Any(v => v.HasValue) ? values : null;
53 }
54
55 private int currentFrameIdx;
56 private int curFrameIncrement;
57 private bool cycleFinished;
58
59 #endregion fields
60
61 #region constructors / finalizer
62
67 public FrameSequence(Frame frame)
68 {
69 frameList = new List<Frame>();
70 frameList.Add(frame);
72 currentFrameIdx = 0;
73 curFrameIncrement = 1;
74 cycleFinished = true;
75 }
76
81 public FrameSequence(List<Frame> frames)
82 {
83 frameList = frames;
85 currentFrameIdx = 0;
86 curFrameIncrement = 1;
87 cycleFinished = true;
88 }
89
90 [OnDeserialized()]
91 private void OnDeserialized(StreamingContext context)
92 {
93 currentFrameIdx = 0;
94 curFrameIncrement = 1;
95 cycleFinished = true;
96 }
97
98 #endregion constructors / finalizer
99
100 #region properties
101
105 [JsonIgnore]
106 public bool CycleFinished
107 {
108 get { return cycleFinished; }
109 }
110
114 [JsonIgnore]
115 public int FrameCount
116 {
117 get
118 {
119 if (frameList == null)
120 SetDefaults();
121
122 return frameList.Count;
123 }
124 }
125
129 [JsonIgnore]
131 {
132 get
133 {
134 if (frameList == null)
135 SetDefaults();
136
137 return frameList[currentFrameIdx];
138 }
139 }
140
144 [JsonIgnore]
146 {
147 get { return currentFrameIdx; }
148 }
149
153 [JsonIgnore]
154 public IList<Frame> FrameList
155 {
156 get { return frameList.AsReadOnly(); }
157 }
158
159 #endregion properties
160
161 #region public methods
162
171 public Frame AddFrame(Tilesheet bmp, string regionName, int xTile, int yTile)
172 {
173 return AddFrame(new Frame(bmp, regionName, xTile, yTile));
174 }
175
183 public Frame AddFrame(Tilesheet bmp, int xTile, int yTile)
184 {
185 return AddFrame(new Frame(bmp, TilesheetRegion.DefaultRegionName, xTile, yTile));
186 }
187
193 public Frame AddFrame(Frame frame)
194 {
195 if (frameList == null)
196 SetDefaults();
197
198 frameList.Add(frame);
199 return frame;
200 }
201
206 public void RemoveFrame(int idx)
207 {
208 if (idx < frameList.Count)
209 {
210 frameList.RemoveAt(idx);
211 if (frameDurations is not null && idx < frameDurations.Count)
212 {
213 frameDurations = new(frameDurations);
214 frameDurations.RemoveAt(idx);
215 }
216 }
217 }
218
222 public void Reset()
223 {
224 currentFrameIdx = 0;
225 curFrameIncrement = 1;
226 }
227
228 #endregion public methods
229
230 #region internal methods
231
232 internal void StopCycle()
233 {
234 cycleFinished = true;
235 }
236
237 internal Frame AdvanceFrame()
238 {
239 switch (SequenceCycleType)
240 {
241 case CycleType.PingPong:
242 currentFrameIdx += curFrameIncrement;
243 if ((currentFrameIdx <= 0) || (currentFrameIdx >= frameList.Count - 1))
244 curFrameIncrement *= -1;
245
246 if (currentFrameIdx < 0)
247 currentFrameIdx = 0;
248
249 if (currentFrameIdx > frameList.Count - 1)
250 currentFrameIdx = frameList.Count - 1;
251
252 cycleFinished = false;
253 break;
254
255 case CycleType.Repeating:
256 if (++currentFrameIdx >= frameList.Count)
257 currentFrameIdx = 0;
258
259 cycleFinished = false;
260 break;
261
262 case CycleType.Simple:
263 if (++currentFrameIdx > frameList.Count - 1)
264 {
265 currentFrameIdx = frameList.Count - 1;
266 cycleFinished = true;
267 }
268 else
269 cycleFinished = false;
270 break;
271
272 default:
273 throw new InvalidOperationException("Invalid CycleType: " + SequenceCycleType.ToString());
274 }
275
276 return frameList[currentFrameIdx];
277 }
278
279 #endregion internal methods
280
281 #region private methods
282
283 private void SetDefaults()
284 {
285 frameList = new List<Frame>();
287 currentFrameIdx = 0;
288 curFrameIncrement = 1;
289 cycleFinished = true;
290 }
291
292 #endregion private methods
293
294 #region indexers
295
301 public Frame this[int frameIdx]
302 {
303 get { return frameList[frameIdx]; }
304 }
305
306 #endregion indexers
307
308 #region IEnumerable Members
309
314 public IEnumerator GetEnumerator()
315 {
316 for (int i = 0; i < frameList.Count; i++)
317 yield return frameList[i];
318 }
319
324 IEnumerator<Frame> IEnumerable<Frame>.GetEnumerator()
325 {
326 return frameList.GetEnumerator();
327 }
328
329 #endregion IEnumerable Members
330}
Represents a rectangular region within a tilesheet that contains a grid of frames.
static readonly string DefaultRegionName
The default name assigned to tilesheet regions when no name is specified.
Represents a tilesheet image and metadata for rendering tiles.
Definition Tilesheet.cs:14
CycleType
Simple is self-terminating; the other two are repeating.
Definition CycleType.cs:11
double? GetDurationSeconds(int index)
Gets the optional display duration for a frame occurrence.
void RemoveFrame(int idx)
Removes the frame at the specified index from the sequence.
Frame AddFrame(Frame frame)
Adds an existing frame to the sequence.
Frame AddFrame(Tilesheet bmp, int xTile, int yTile)
Creates and adds a new frame to the sequence using tilesheet coordinates.
void Reset()
Resets the sequence to its initial state, starting from the first frame.
IList< Frame > FrameList
Gets a read-only view of the list of frames in the sequence.
Frame CurrentFrame
Gets the frame currently active in the animation sequence.
FrameSequence(Frame frame)
Initializes a new instance of the FrameSequence struct with a single frame.
int FrameCount
Gets the total number of frames in the sequence.
CycleType SequenceCycleType
The type of cycle pattern used when animating through the frame sequence.
void SetDurationSeconds(int index, double? seconds)
Sets a positive display duration, or null to use the cycle default.
Frame AddFrame(Tilesheet bmp, string regionName, int xTile, int yTile)
Creates and adds a new frame to the sequence using tilesheet coordinates.
FrameSequence(List< Frame > frames)
Initializes a new instance of the FrameSequence struct with a collection of frames.
int CurrentFrameIdx
Gets the zero-based index of the current frame in the sequence.
IEnumerator GetEnumerator()
Returns an enumerator that iterates through the frame sequence.
bool CycleFinished
Gets a value indicating whether the animation cycle has finished playing through the sequence.
Represents the source Tilesheet and its coordinates to render on a destination.
Definition Frame.cs:12