v3.2.4: updates to improve handling of Android cutouts:

- HP bar can now resize-reposition to prevent being cut off
- menu pane can now move inward to prevent being cut off
- increased buff bar cut off sensitivity
- slightly increased 'large cutout' permissiveness
This commit is contained in:
Evan Debenham
2025-09-14 11:58:11 -04:00
parent f83cd78243
commit 2c0f1263a7
6 changed files with 70 additions and 17 deletions

View File

@@ -121,9 +121,10 @@ public class AndroidPlatformSupport extends PlatformSupport {
for (Rect r : cutout.getBoundingRects()){
//use abs as some cutouts can apparently be returned inverted
int cutoutSize = Math.abs(r.height() * r.width());
//display cutouts are considered large if they take up more than 0.605% of the screen
//display cutouts are considered large if they take up more than 0.667% of the screen
//in reality we want less than about 0.5%, but some cutouts over-report their size
if (cutoutSize*165 >= screenSize){
//Pixel devices especially =S
if (cutoutSize*150 >= screenSize){
largeCutout = true;
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@@ -368,22 +368,39 @@ public class GameScene extends PixelScene {
int uiSize = SPDSettings.interfaceSize();
//Some more medium sized display cutouts can obstruct the buff bar, so we limit the length
// of the 1st row in some cases
//display cutouts can obstruct various UI elements, so we need to adjust for that sometimes
float menuBarMaxLeft = uiCamera.width-insets.right-MenuPane.WIDTH;
int hpBarMaxWidth = 50; //default max width
float buffBarTopRowMaxWidth = 50; //default max width
if (largeInsetTop != insets.top){
//most notably iOS's Dynamic island, which must exist in this case
//iOS's Dynamic island badly obstructs the first buff bar row
if (DeviceCompat.isiOS()){
//TODO bad to hardcode this atm, need to change this so platformsupport returns cutout dimensions
buffBarTopRowMaxWidth = 15;
} else if (DeviceCompat.isAndroid()) {
//some android hole punches can also be big too
//Android hole punches are of varying size and may obstruct the menu, HP bar, or buff bar
RectF cutout = Game.platform.getDisplayCutout().scale(1f / defaultZoom);
//if the cutout is positioned to obstruct the menu bar
if (cutout.top < 20
&& cutout.left < menuBarMaxLeft + MenuPane.WIDTH
&& cutout.right > menuBarMaxLeft) {
menuBarMaxLeft = Math.min(menuBarMaxLeft, cutout.left - MenuPane.WIDTH);
//make sure we have space to actually move it though
menuBarMaxLeft = Math.max(menuBarMaxLeft, PixelScene.MIN_WIDTH_P-MenuPane.WIDTH);
}
//if the cutout is positioned to obstruct the HP bar
if (cutout.left < 78
&& cutout.top < 4
&& cutout.right > 32) {
//subtract starting position, but add a bit back due to end of bar
hpBarMaxWidth = Math.round(cutout.left - 32 + 4);
hpBarMaxWidth = Math.max(hpBarMaxWidth, 21); //cannot go below 21 (30 effective)
}
//if the cutout is positioned to obstruct the buff bar
if (cutout.left < 80
&& cutout.top < 10
&& cutout.right > 32
&& cutout.bottom > 12) {
&& cutout.bottom > 11) {
buffBarTopRowMaxWidth = cutout.left - 32; //subtract starting position
}
}
@@ -396,11 +413,24 @@ public class GameScene extends PixelScene {
menu = new MenuPane();
menu.camera = uiCamera;
menu.setPos( uiCamera.width-MenuPane.WIDTH-insets.right, screentop);
menu.setPos( menuBarMaxLeft, screentop);
add(menu);
float extraRight = uiCamera.width - (menuBarMaxLeft + MenuPane.WIDTH);
if (extraRight > 0){
SkinnedBlock bar = new SkinnedBlock(extraRight, 20, TextureCache.createSolid(0x88000000));
bar.x = uiCamera.width - extraRight;
bar.camera = uiCamera;
add(bar);
PointerArea blocker = new PointerArea(uiCamera.width - extraRight, 0, extraRight, 20);
blocker.camera = uiCamera;
add(blocker);
}
status = new StatusPane( SPDSettings.interfaceSize() > 0 );
status.camera = uiCamera;
StatusPane.hpBarMaxWidth = hpBarMaxWidth;
StatusPane.buffBarTopRowMaxWidth = buffBarTopRowMaxWidth;
status.setRect(insets.left, uiSize > 0 ? uiCamera.height-39-insets.bottom : screentop, uiCamera.width - insets.left - insets.right, 0 );
add(status);

View File

@@ -73,14 +73,14 @@ public class DangerIndicator extends Tag {
protected void layout() {
super.layout();
icon.x = right() - 10;
icon.x = left() + 14;
icon.y = y + (height - icon.height) / 2;
placeNumber();
}
private void placeNumber() {
number.x = right() - 11 - number.width();
number.x = left() + 13 - number.width();
number.y = y + (height - number.baseLine()) / 2f;
PixelScene.align(number);
}

View File

@@ -208,6 +208,7 @@ public class MenuPane extends Component {
}
danger.setPos( x + WIDTH - danger.width(), y + bg.height + 1 );
danger.setSize( camera.width - danger.width(), danger.height());
}
public void pickup(Item item, int cell) {

View File

@@ -78,8 +78,10 @@ public class StatusPane extends Component {
private boolean large;
//lower the buff indicator to avoid larger cutouts (e.g. iPhone dynamic island)
public static float cutoutOffset;
//potentially shrinks and/or repositions the hp bar to avoid some cutouts
public static int hpBarMaxWidth = 50;
private Image hpCutout;
//potentially cuts off the top row of the the buff indicator to avoid some cutouts
public static float buffBarTopRowMaxWidth = 50;
public StatusPane( boolean large ){
@@ -90,10 +92,13 @@ public class StatusPane extends Component {
this.large = large;
if (large) bg = new NinePatch( asset, 0, 64, 41, 39, 33, 0, 4, 0 );
//right part is transparent now so Ninepatching doesn't actually do anything
else bg = new NinePatch( asset, 0, 0, 128, 38, 85, 0, 45, 0 );
else bg = new NinePatch( asset, 0, 0, 82, 38, 32, 0, 5, 0 );
add( bg );
hpCutout = new Image(asset, 90, 0, 12, 9);
hpCutout.visible = false;
add(hpCutout);
heroInfo = new Button(){
@Override
protected void onClick () {
@@ -179,7 +184,7 @@ public class StatusPane extends Component {
bg.x = x;
bg.y = y;
if (large) bg.size( 160, bg.height ); //HP bars must be 128px wide atm
else bg.size( width, bg.height );
else bg.size(hpBarMaxWidth+32, bg.height ); //default max right is 50px health bar + 32
avatar.x = bg.x - avatar.width / 2f + 15;
avatar.y = bg.y - avatar.height / 2f + 16;
@@ -216,7 +221,23 @@ public class StatusPane extends Component {
exp.x = x+2;
exp.y = y+30;
hp.x = shieldedHP.x = rawShielding.x = x + 30;
float hpleft = x + 30;
if (hpBarMaxWidth < 82){
//the class variable assumes the left of the bar can't move, but we can inset it 9px
int hpWidth = (int)hpBarMaxWidth;
if (hpWidth <= 41){
hpleft -= 9;
hpWidth += 9;
hpCutout.visible = true;
hpCutout.x = hpleft - 2;
hpCutout.y = y;
}
hp.frame(50-hpWidth, 40, 50, 4);
shieldedHP.frame(50-hpWidth, 44, 50, 4);
rawShielding.frame(50-hpWidth, 44, 50, 4);
}
hp.x = shieldedHP.x = rawShielding.x = hpleft;
hp.y = shieldedHP.y = rawShielding.y = y + 2;
hpText.scale.set(PixelScene.align(0.5f));
@@ -234,7 +255,7 @@ public class StatusPane extends Component {
heroInfoOnBar.setRect(heroInfo.right(), y, 50, 9);
buffs.firstRowWidth = buffBarTopRowMaxWidth;
buffs.setRect( x + 31, y + 8 + cutoutOffset, 50, 15 );
buffs.setRect( x + 31, y + 8, 50, 15 );
busy.x = x + 1;
busy.y = y + 37;