Skip to content

FlxNestedSprite movement calculations errors #422

@47rooks

Description

@47rooks

I was reading this code the other day and noticed a that in update, preUpdate and postUpdate are call once per level of nesting in the hierarchy of objects in a FlxNestedSprite. So the top level object calls them once, the second twice, the third three times and so on. I traced it in the attached program and it's so. This should have resulted in erroneous motion calculations when relativeVelocity is non-0. I tested that and it is also true. If you set _fns2.relativeVelocity to 10. and run the program the _fns2 sprite travels approximately twice as far relative to _fns1 as it should. If instead you make _fns3.relativeVelocity = 10 and leave _fns2 relativeVelocity = 0, the _fns3 will travel 3 times as far as it should relative to _fns1 as it should. This is consistent with multiple calls to updateMotion() at each level.

This is a simple PlayState demonstrating the issue. The lib versions involved are:

Haxe 4.3.3
flixel-addons: [3.2.1]
flixel: [5.6.2]

package;

import flixel.FlxSprite;
import flixel.FlxState;
import flixel.addons.display.FlxNestedSprite;
import flixel.tweens.FlxTween;
import flixel.tweens.misc.NumTween;
import flixel.util.FlxColor;
import haxe.Timer;

class FlxDebugNestedSprite extends FlxNestedSprite
{
	var _name:String;

	public function new(name:String)
	{
		super();
		_name = name;
	}

	override public function preUpdate(elapsed:Float):Void
	{
		// trace('Starting preUpdate ${_name}');
		super.preUpdate(elapsed);
		// trace('Ending preUpdate ${_name}');
	}

	override public function update(elapsed:Float):Void
	{
		// trace('Starting update ${_name} at ${Timer.stamp()}');
		super.update(elapsed);
		// trace('Ending update ${_name} at ${Timer.stamp()}');
	}

	override public function postUpdate(elapsed:Float):Void
	{
		// trace('Starting postUpdate ${_name}');
		super.postUpdate(elapsed);
		// trace('Ending postUpdate ${_name}');
	}

	override function updateMotion(elapsed:Float):Void
	{
		// trace('Starting updateMotion ${_name}');
		super.updateMotion(elapsed);
		// trace('Ending updateMotion ${_name}');
	}
}

class PlayState extends FlxState
{
	var _fns1:FlxDebugNestedSprite;
	var _fns2:FlxDebugNestedSprite;
	var _fns3:FlxDebugNestedSprite;
	var _fns4:FlxDebugNestedSprite;

	override public function create()
	{
		super.create();

		_fns1 = new FlxDebugNestedSprite('fns1');
		_fns1.makeGraphic(100, 100, FlxColor.WHITE);
		_fns1.setPosition(0, 100);

		_fns2 = new FlxDebugNestedSprite('fns2');
		_fns2.makeGraphic(40, 40, FlxColor.BLUE);
		_fns2.relativeX = _fns2.relativeY = 50;

		_fns3 = new FlxDebugNestedSprite('fns3');
		_fns3.makeGraphic(10, 10, FlxColor.RED);
		_fns3.relativeX = 30;

		_fns4 = new FlxDebugNestedSprite('fns4');
		_fns4.makeGraphic(10, 10, FlxColor.RED);
		_fns4.relativeY = 30;

		_fns2.add(_fns3);
		_fns2.add(_fns4);
		_fns1.add(_fns2);

		add(_fns1);

		// Various motion tests

		// There is something odd with tweening which results in _fns3 and _fns4 being out of position.
		// FlxTween.tween(_fns1, {x: 600}, 1.0, {type: PINGPONG});

		// Basic white block speed
		_fns1.velocity.x = 200;

		// Relative speed tests. Uncomment _fns2 for see the example with doubled up relative distance.
		// With 10 px/sec relative to _fns1 the final displacement change in x should be about 30 pixels
		// but it is about 60.
		_fns2.relativeVelocity.x = 10;

		// Relative speed tests. Uncomment _fns3 for see the example with tripled up relative distance.
		// With 10 px/sec relative to _fns1 the final displacement change in x should be about 30 pixels
		// but it is about 90.
		// _fns3.relativeVelocity.x = 10;
	}

	override public function update(elapsed:Float)
	{
		super.update(elapsed);

		// Travelling about 200 pixels per second this gives about 3 seconds elapsed between sides
		// of the game window.
		if (_fns1.x <= 0 || _fns1.x > 600)
		{
			_fns1.velocity.x *= -1.0;
			_fns2.relativeVelocity.x *= -1.0;
			_fns3.relativeVelocity.x *= -1.0;

			// Diff the values in consecutive prints of this debug.
			trace('${Timer.stamp()}:_fns1.x=${_fns1.x} and _fns2.x=${_fns2.x} and _fns3.x=${_fns3.x}');
		}
	}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions