Skip to content

Commit 203f45d

Browse files
authored
FlxAnimationController: fix off-by-one and negative modulo bugs (#3554)
* fix frame indexing and modulo behavior fix frame indexing and modulo behavior * clamp negative frameIndex and warn on out-of-range
1 parent fb9e7ea commit 203f45d

File tree

2 files changed

+78
-2
lines changed

2 files changed

+78
-2
lines changed

flixel/animation/FlxAnimationController.hx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ class FlxAnimationController implements IFlxDestroyable
241241
var framesToAdd:Array<Int> = frames;
242242
var hasInvalidFrames = false;
243243
var i = framesToAdd.length;
244-
while (i-- >= 0)
244+
while (i-- > 0)
245245
{
246246
final frame = framesToAdd[i];
247247
if (frame >= numFrames)
@@ -819,7 +819,17 @@ class FlxAnimationController implements IFlxDestroyable
819819
{
820820
if (_sprite.frames != null && numFrames > 0)
821821
{
822-
Frame = Frame % numFrames;
822+
if (Frame < 0)
823+
{
824+
FlxG.log.warn('frameIndex must be a positive number, got $Frame, using 0, instead');
825+
Frame = 0;
826+
}
827+
else if (Frame >= numFrames)
828+
{
829+
FlxG.log.warn('frameIndex must be less than $numFrames, got $Frame, wrapping to ${Frame % numFrames}, instead');
830+
Frame = Frame % numFrames;
831+
}
832+
823833
_sprite.frame = _sprite.frames.frames[Frame];
824834
frameIndex = Frame;
825835
fireCallback();

tests/unit/src/flixel/animation/FlxAnimationControllerTest.hx

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -278,6 +278,72 @@ class FlxAnimationControllerTest extends FlxTest
278278
Assert.isTrue (sprite.animation.exists("anim4"), 'missing "anim4"');
279279
}
280280

281+
@Test // #3554
282+
function testAddAllValidFrames()
283+
{
284+
var bitmapData = new BitmapData(4, 1);
285+
sprite.loadGraphic(bitmapData, true, 1, 1);
286+
287+
sprite.animation.add("test", [0, 1, 2, 3]);
288+
289+
var anim = sprite.animation.getByName("test");
290+
Assert.isNotNull(anim);
291+
FlxAssert.arraysEqual([0, 1, 2, 3], anim.frames);
292+
}
293+
294+
@Test // #3554
295+
function testAddSomeInvalidFrames()
296+
{
297+
var bitmapData = new BitmapData(4, 1);
298+
sprite.loadGraphic(bitmapData, true, 1, 1);
299+
300+
sprite.animation.add("test", [0, 4, 2, 5, 3]);
301+
302+
var anim = sprite.animation.getByName("test");
303+
Assert.isNotNull(anim);
304+
FlxAssert.arraysEqual([0, 2, 3], anim.frames);
305+
}
306+
307+
@Test // #3554
308+
function testAddSingleValidFrame()
309+
{
310+
var bitmapData = new BitmapData(4, 1);
311+
sprite.loadGraphic(bitmapData, true, 1, 1);
312+
313+
sprite.animation.add("test", [0]);
314+
315+
var anim = sprite.animation.getByName("test");
316+
Assert.isNotNull(anim);
317+
FlxAssert.arraysEqual([0], anim.frames);
318+
}
319+
320+
@Test // #3554
321+
function testAddAllInvalidFrames()
322+
{
323+
loadSpriteSheet();
324+
325+
sprite.animation.add("test", [5, 6, 7]);
326+
327+
var anim = sprite.animation.getByName("test");
328+
Assert.isNull(anim);
329+
}
330+
331+
@Test // #3554
332+
function testFrameIndexNegativeClampsToZero()
333+
{
334+
var bitmapData = new BitmapData(4, 1);
335+
sprite.loadGraphic(bitmapData, true, 1, 1);
336+
337+
sprite.animation.add("test", [0, 1, 2, 3]);
338+
sprite.animation.play("test");
339+
340+
sprite.animation.frameIndex = -1;
341+
342+
Assert.areEqual(0, sprite.animation.frameIndex);
343+
sprite.animation.frameIndex = -4;
344+
Assert.areEqual(0, sprite.animation.frameIndex);
345+
}
346+
281347
function loadSpriteSheet():Void
282348
{
283349
var bitmapData = new BitmapData(2, 1);

0 commit comments

Comments
 (0)