Android Scaling Issue with OpenFL and HaxeFlixel

I am unable to figure out how to scale properly for Android devices (and possibly iOS, as I don’t have one to test). In my project.xml, I have the default settings for the Android screen size:

<window if="mobile" orientation="portrait" fullscreen="true" width="0" height="0" />

However, the issue is that I want to work with a 640 x 960 resolution in mind, and I want it to be scaled to that. And when I run it with this setting, it looks so much smaller than it does on desktop when I test it. So I instead tried to set it to this:

<window if="mobile" orientation="portrait" fullscreen="true" width="640" height="960" />

The issue then becomes a horizontal letterbox scaling style with black bars on the top and bottom, which is quite unattractive. I read on the forums that this is due to the on screen bottom navbar that some Androids have (mine included). And I read something about handling event.RESIZE events, which I do not understand how to work with. I would like to just develop for the 640 x 960.

Just to be clear, I am a rookie HaxeFlixel developer (clearly), but I am experienced in making apps, and I come from Corona SDK. I LOVE Haxe, and would really like to work with HaxeFlixel. And perhaps the issue is that I’m operating with Corona SDK’s scaling in mind. If you’re not familiar with the way Corona SDK works, the simple version is this: You develop with a certain screen size in mind, and often get black bars on the sides, which you can then fill in. This would be exactly what I’m comfortable with, and that is what it seems RatioScaleMode(true) is for. That way I can artificially fill in the missing spaces with filler, but it only works when the letterbox is vertical and has the black bars on the sides.

I have a test PlayState that I’m working with to learn that I will attach below. Thank you for any help!

package;

import flixel.FlxG;
import flixel.FlxSprite;
import flixel.FlxState;
import flixel.util.FlxColor;
import flixel.text.FlxText;
import flixel.system.scaleModes.FillScaleMode;

class PlayState extends FlxState
{
	var rect:FlxSprite;
	var header:FlxSprite;
	var headerText:FlxText;

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

		#if desktop
			FlxG.mouse.useSystemCursor = true;
		#end
		FlxG.scaleMode = new FillScaleMode();

		// Create a background
		this.rect = new FlxSprite();
		this.rect.makeGraphic(FlxG.width * 2, FlxG.height * 2, 0xFFFFFFFF);
		this.add(rect);

		// Create a header bar
		this.header = new FlxSprite();
		this.header.makeGraphic(FlxG.width, 100, 0xFF314970);
		this.add(header);

		// Create the header text
		this.headerText = new FlxText(0, 5, FlxG.width);
		this.headerText.text = "Testing!";
		this.headerText.setFormat("assets/fonts/PassionOne-Regular.ttf", 70, 0xFFFFFFFF, FlxTextAlign.CENTER, FlxTextBorderStyle.NONE, 0xFF000000);
		this.headerText.setBorderStyle(FlxTextBorderStyle.SHADOW, FlxColor.BLACK, 2);
		this.add(headerText);
		
	}

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

Current OpenFL releases do letterboxing automatically if your content has an exact size (such as 640x960). The black bars you’re seeing might be from OpenFL.

Otherwise, you need to allow window width and height in your project file to be zero, and then use Event.RESIZE events on the stage to handle the resize yourself. This could be as simple as scaling and centering your game content. If you handle the resizing this way, you can create a custom background that is not black for the additional space. Does this make sense?

Thanks for the quick reply. And yes! That does make some sense. If it is openfl, how do you suggest I counter it? I think I’ve seen something like openfl.Lib.current.stage.scaleMode = NO_SCALE. I know it’s not exactly like that, but I can look at the documentation for that. Didn’t know if that applies to HaxeFlixel. For the second part that you mentioned, how would I handle the scaling? Is there a method within HaxeFlixel / OpenFL to do that for you, or is that something where I would figure out the math for scaling myself? And lastly, how would set up the event.RESIZE? I often look at the API docs and they’re very helpful, but sometimes it’s hard to find specific things. Is it something as simple as adding an event listener to the scene? Something like this.addEventListener(event.RESIZE, resizeMethod)?

We don’t support all stage.scaleMode values properly – in the future, that would be the way to control this, but in the meantime, it’s based upon <window resizable="true" /> and <window width="" height="" />

If you do not set either resizable or width/height, OpenFL will not letterbox, and will expect you to handle the resize events.

You can listen for a resize like this:

stage.addEventListener (Event.RESIZE, stage_onResize);

I believe you could use code something like this (where content is a Sprite or other object with all of your game content)

private function stage_onResize (event:Event):Void {
	
	var contentWidth = 640;
	var contentHeight = 960;
	
	var maxScaleX = stage.stageWidth / contentWidth;
	var maxScaleY = stage.stageHeight / contentHeight;
	var scale;
	
	if (maxScaleX < maxScaleY) {
		
		scale = maxScaleX;
		
	} else {
		
		scale = maxScaleY;
		
	}
	
	content.scaleX = scale;
	content.scaleY = scale;
	content.x = stage.stageWidth / 2 - (contentWidth * scale) / 2;
	content.y = stage.stageHeight / 2 - (contentHeight * scale) / 2;
	
}

The idea is to find the right scale value to use that will fill as much of the screen as possible without clipping. Then you need to scale all the content up to this size, while also centering it

Got it! Thanks so much! You were very helpful :slight_smile:

Actually, sorry. One more question. What do you mean by “content is a Spite other object”? Is “Sprite other” a typo, or do you mean a group?

Yeah, I was missing an “or” in there, “content is a Sprite or other object”

If you have everything inside of a Sprite called Game, scale that up and position it. I am not an expert in Flixel, so perhaps there’s an FlxContainer or some other display object that has all of your game in it, and can be scaled :slight_smile: