Skip to content

FlxNestedSprite movement calculations errors #422

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

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions