[Solved] Bug with FlxButton and FlxCamera



  • Hi,

    I'm using a FlxZoomCamera to be able to zoom on the game while I also have a FlxCamera to draw the HUD above that.
    The game and the HUD are far away one from each other.
    In my HUD, I have a FlxText, a FlxSprite and a FlxButton. The problem is that the FlxButton appears twice in both cameras.

    I've wrote a little code so you can easily try:

    package;
    
    import flixel.FlxG;
    import flixel.FlxCamera;
    import flixel.addons.display.FlxZoomCamera;
    import flixel.FlxSprite;
    import flixel.FlxState;
    import flixel.text.FlxText;
    import flixel.ui.FlxButton;
    import flixel.FlxObject;
    import flixel.util.FlxColor;
    
    class PlayState extends FlxState
    {
    	override public function create():Void 
    	{
    		// Fake game to zoom in
    		var game:FlxSprite = new FlxSprite(1000, 0);
    		game.makeGraphic(200, 100, FlxColor.BLUE);
    		add(game);
    		
    		// HUD with text, sprite and button
    		var text:FlxText = new FlxText(220, 200, 200, "some text");
    		add(text);
    		var sprite:FlxSprite = new FlxSprite(220, 250);
    		sprite.makeGraphic(100, 20, FlxColor.RED);
    		add(sprite);
    		var button:FlxButton = new FlxButton(220, 300, "button");
    		add(button);
    
    		// Setup cameras
    		FlxG.cameras.list[0].kill();
    
    		var cameraGame:FlxZoomCamera = new FlxZoomCamera(0, 0, 640, 480, 2);
    		var gameCenter:FlxObject = new FlxObject(game.x + game.width / 2, game.y + game.height / 2);
    		add(gameCenter);
    		cameraGame.target = gameCenter;
    		FlxG.cameras.add(cameraGame);
    
    		var cameraHUD:FlxCamera = new FlxCamera();
    		cameraHUD.bgColor = 0x0; // transparent
    		FlxG.cameras.add(cameraHUD);
    	}
    }
    

    Right now, the only answer I have is to write my own buttons by using FlxSprite and click events... But I need a lot of features from FlxButton for my game and rewritting everything is a bit messy...
    Why does the FlxButton behave like that?



  • FIrst of all, I would setup the cameras by resetting to camereGame instead of:

    FlxG.cameras.list[0].kill();
    

    Do this after creating cameraGame and also set the default cameras to it:

    FlxG.cameras.reset(cameraGame);
    FlxG.defaultCameras = [cameraGame];
    

    It seems only the button appear twice in both cameras but I believe all of the HUD elements like the text and the sprite also appear twice but maybe on top of the others in the other camera so you can't see it. To fix that, set the cameras list which the HUD elements will be drawn on like this:

    hudElement.cameras = [cameraHUD];
    


  • Thanks for your time.

    So replacing FlxG.cameras.list[0].kill(); and FlxG.cameras.add(cameraGame); by FlxG.cameras.reset(cameraGame); is working.
    When I trace Flxg.cameras.list, I have my two cameras.

    FlxG.defaultCameras doesn't exist. I've replaced it by FlxCamera.defaultCameras
    But if I add FlxCamera.defaultCameras = [cameraGame]; the game appears above the HUD.

    Maybe it has to do with your last bit of code hudElement.cameras = [cameraHUD]; but I don't understand what hudElement should be in the code I provided.

    Last thing, I've already played a lot with FlxZoomCamera and FlxButton and I can confirm that FlxText and FlxSprite don't have that problem. They're not on top one of each other in each viewport. The cameraGame is zoomed so elements that appears twice are obvious. I've also moved the cameras to verify everything.

    Here's a screenshot of what's happening:
    alt text
    The blue box is the game, far away on x coordinates, and zoomed by the FlxCameraZoom.
    The rest is the HUD: Text, red sprite, button.
    I've already tried switching game and HUD positions.
    Only the button appears twice.

    As I said, if I replace buttons by my own code using FlxSprite and event calls for mouse click, everything's fine. But that doesn't get rid of that bug with FlxButton.



  • About FlxG.defaultCameras, yeah it's my bad, it's actually FlxCamera.defaultCameras.
    By hudElement, I mean the button, the "some text" and the red sprite as you stated.



  • Oh cool!
    I didn't know that you could choose the camera an element should be rendered with.
    Now it works, only by adding button.cameras[cameraHUD].
    Thank you :)

    (It's still weird that the button behave like that though)



  • Sorry, I have one more question:

    I wrote a custom slider that extends FlxGroup. Inside I have again the same three things: text, sprite and button. The problem is that when I create the slider and "attach" it to the cameraHUD, the button inside the Slider have the same problem as before, it appears in the viewports of cameraGame and cameraHUD.
    Here's what I did to add my Slider inside the FlxState:

    slideTime = new Slider(320, 224, "time");
    slideTime.cameras = [cameraHUD];
    add(slideTime);
    

    Do I have to scan for everything inside the Slider from the FlxState and attach everything to cameraHUD? Something like:

    private function setCameraForGroup(group:FlxGroup, camera:FlxCamera):Void
    {
    	for (thing in group) 	thing.cameras = [camera];
    }
    

    Or is there a simplier way to repair that?

    Thanks

    Edit:
    And I have the same problem with FlxSubState. The buttons inside the substate are appearing twice.
    Here's what I tried:

    substate = new FighterPicker(currentFace, chooseCover, chooseCustom);
    substate.cameras = [cameraHUD];
    FlxG.state.openSubState(substate);
    

    And that does not work for the buttons inside the substate.

    Edit 2:
    In my first example, I've replaced the FlxZoomCamera by a classic FlxCamera with a zoom level and if I don't attach the button to the camera, it still appears in double and it only occurs with buttons. I've changed the name of the topic accordingly...



  • Seriously, that bug with FlxButton and FlxCamera is a mess...

    For example, in my game, I have a playState:FlxState.
    Inside I have a FlxZoomCamera for the game and a FlxCamera for the HUD.

    When I press pause, I open a pauseScreen:FlxSubState.
    And last but not least, I have some kind of coverflow in the subState: coverflow:FlxGroup and each and every covers in that coverflow are FlxButton.

    Guess what, all the covers are appearing twice in the FlxSubstate because of the two cameras in the FlxState above. So how do I tell the covers to be attached to the HUD camera from the FlxState?

    Or do I have to retrieve the camera in the FlxSubState and do that from there? I'm using that coverflow in the title screen too, so I don't always have two cameras...

    Edit:
    So I wrote another example from the first code I provided to try to understand what's going on:

    package;
    
    import flixel.FlxG;
    import flixel.FlxCamera;
    import flixel.addons.display.FlxZoomCamera;
    import flixel.FlxSprite;
    import flixel.FlxState;
    import flixel.text.FlxText;
    import flixel.ui.FlxButton;
    import flixel.FlxObject;
    import flixel.util.FlxColor;
    import flixel.group.FlxGroup;
    import flixel.tweens.FlxTween;
    
    class PlayState extends FlxState
    {
    	override public function create():Void 
    	{
    		// Fake game to zoom in
    		var game:FlxSprite = new FlxSprite(1000, 0);
    		game.makeGraphic(200, 100, FlxColor.BLUE);
    		game.alpha = .6;
    		add(game);
    
    		var cameraGame:FlxCamera = new FlxCamera(-300, -300, 640, 480, 2);
    		FlxG.cameras.reset(cameraGame);
    
    		var gameCenter:FlxObject = new FlxObject(game.x + game.width / 2, game.y + game.height / 2);
    		add(gameCenter);
    		cameraGame.target = gameCenter;
    
    		var cameraHUD:FlxCamera = new FlxCamera();
    		cameraHUD.bgColor = 0x0; // transparent
    		FlxG.cameras.add(cameraHUD);
    
    		// Tweens to move the two cameras around
    		FlxTween.tween(gameCenter, { x:1200 }, 3, { type:FlxTween.PINGPONG } );
    		FlxTween.tween(cameraHUD, { y:100 }, 3, { type:FlxTween.PINGPONG } );
    
    		// HUD with text, sprite and button
    		var text:FlxText = new FlxText(220, 200, 200, "some text");
    		add(text);
    		var sprite:FlxSprite = new FlxSprite(220, 250);
    		sprite.makeGraphic(100, 20, FlxColor.RED);
    		add(sprite);
    		var button:FlxButton = new FlxButton(220, 300, "button");
    		add(button);
    
    		// I know that in this example, I can use that:
    		// button.cameras = [cameraHUD];
    		// but it's not helping for my problem
    	}
    }
    

    And here's an animated gif with the weird zoomed button, not moving with the rest. It has become some kind of ghost...

    http://i.giphy.com/3oEjHSFDV6WtCAfmmc.gif

    The blue box is half transparent so no one hides behind it.
    What's going on with the button?



  • I'm getting closer: the bug is already there with only one camera and no zoom:

    override public function create():Void 
    {
    	// Fake game to zoom in
    	var game:FlxSprite = new FlxSprite(1000, 0);
    	game.makeGraphic(200, 100, FlxColor.BLUE);
    	game.alpha = .6;
    	add(game);
    
    	var cameraGame:FlxCamera = new FlxCamera(0, 0, 640, 480);
    	FlxG.cameras.reset(cameraGame);
    	var gameCenter:FlxObject = new FlxObject(game.x + game.width / 2, game.y + game.height / 2);
    	add(gameCenter);
    	cameraGame.target = gameCenter;
    
    	FlxTween.tween(gameCenter, { x:1200 }, 3, { type:FlxTween.PINGPONG } );
    
    	// HUD with text, sprite and button
    	var text:FlxText = new FlxText(220, 200, 200, "some text");
    	add(text);
    	var sprite:FlxSprite = new FlxSprite(220, 250);
    	sprite.makeGraphic(100, 20, FlxColor.RED);
    	add(sprite);
    	var button:FlxButton = new FlxButton(220, 300, "button");
    	add(button);
    }
    

    The button has nothing to do here as it is not even filmed by the remaining camera:
    alt text

    Edit:
    I've test all kinds of buttons, and there is the same problem with each one. So now I'm digging in their basis: FlxTypedButton.



  • Nailed it!

    The problem seems to come from scrollFactor.set() at line 215.
    https://github.com/HaxeFlixel/flixel/blob/dev/flixel/ui/FlxButton.hx#L215

    If I change the scrollFactor to (1, 1), the button only appears where he is supposed to, and not on every camera's viewports.
    So I suppose it's not a bug and that"s how the button is supposed to work since it is considered as a UI element. Here's the explanations inside FlxObject:

    public var scrollFactor(default, null):FlxPoint;
    Controls how much this object is affected by camera scrolling. 0 = no movement (e.g. a background layer), 1 = same movement speed as the foreground. Default value is (1,1), except for UI elements like FlxButton where it's (0,0).


Log in to reply
 

Looks like your connection to HaxeFlixel was lost, please wait while we try to reconnect.