Hey guys,
Im trying to make a progress bar. I followed this tutorial but it is not responsive and I find a few problems when I try to make it responsive
Work with pixels width is not appropriate to keep aspect ratio
Work with scales deform the element
Masks are not an option because pixelize the element
Is there a way built into the engine to do this?
Thanks.
1 Like
Hi @Javier_Heras ,
You can try making a feature request about this, though most likely it’s a application specific since the progress bar isn’t an engine element.
Have you tried playing with the screen component ref resolution and scale blend?
1 Like
What do you mean by ‘responsive’?
1 Like
I mean the way to adapt element sizes for good rendering on different screen sizes. Responsive web design - Wikipedia
So you are looking for something that would keep aspect ratio or doesn’t stretch the pixels? If the latter, you could use 9 sliced sprites instead.
If you want to keep aspect ratio, you will unfortunately need to do your own logic where after a UI reflow, the code would resize the elements
I’ve done something similar here specifically for the layout group children:
var LayoutChildPreserveAspectRatio = pc.createScript('layoutChildPreserveAspectRatio');
LayoutChildPreserveAspectRatio.attributes.add("originalWidth", {type:"number"});
LayoutChildPreserveAspectRatio.attributes.add("originalHeight", {type:"number"});
// initialize code called once per entity
LayoutChildPreserveAspectRatio.prototype.initialize = function() {
this.heightWidthRatio = this.originalHeight / this.originalWidth;
this.widthHeightRatio = this.originalWidth / this.originalHeight;
this._triggerReflow = false;
this._orientation = this.entity.parent.layoutgroup.orientation;
if (this._orientation === pc.ORIENTATION_VERTICAL) {
this.entity.element.on("set:calculatedHeight", this.OnResizeVertical, this);
} else {
this.entity.element.on("set:calculatedWidth", this.OnResizeHorizontal, this);
}
};
LayoutChildPreserveAspectRatio.prototype.update = function(dt) {
if (this._triggerReflow) {
this.entity.parent.layoutgroup._scheduleReflow();
this._triggerReflow = false;
}
};
LayoutChildPreserveAspectRatio.prototype.OnResizeVertical = function(height) {
var width = height * this.widthHeightRatio;
if (width !== this.entity.calculatedWidth) {
this.entity.layoutchild.minWidth = width;
this.entity.layoutchild.maxWidth = width;
}
// Force a reflow next frame
this._triggerReflow = true;
};
LayoutChildPreserveAspectRatio.prototype.OnResizeHorizontal = function(width) {
var height = width * this.heightWidthRatio;
this.entity.layoutchild.minHeight = height;
this.entity.layoutchild.maxHeight = height;
// Force a reflow next frame
this._triggerReflow = true;
};
2 Likes
I’m not sure if you are refering to default loading bar to load game. Im speaking about progress bar with element component; Like player experience, player life, etc.
The main problem to readapt correctly is anchors positions.
I cannot make a simple equation like progressBarWidth / 1080 * currentDeviceWidth.
This anchors as example:
for a 1080 width pixels resolution the element width is 230, for a 2160 pixels resolution the element width si 341
Currently got keep aspect ratio working at the moment: https://playcanvas.com/editor/scene/1332216
The bar is trickier
2 Likes
Something like this (responsive width)?
Same project link as above
I think there are better ways to do it rather than use ratio but you should be able to get the idea here
2 Likes
Looks nice, @yaustar how did you approach this?
1 Like
yaustar
February 9, 2022, 4:48pm
10
Project link: https://playcanvas.com/editor/scene/1332216
There’s a private event on the element component that is undocumented when the calculated width/height is set (usually by resizes of the screen or changes to dimensions somehow)
this.entity._dirtifyLocal();
if (updateMargins) {
const p = this.entity.getLocalPosition();
const pvt = this._pivot;
this._margin.x = p.x - this._calculatedWidth * pvt.x;
this._margin.z = (this._localAnchor.z - this._localAnchor.x) - this._calculatedWidth - this._margin.x;
}
this._flagChildrenAsDirty();
this.fire('set:calculatedWidth', this._calculatedWidth);
this.fire('resize', this._calculatedWidth, this._calculatedHeight);
}
_setCalculatedHeight(value, updateMargins) {
if (Math.abs(value - this._calculatedHeight) <= 1e-4)
return;
this._calculatedHeight = value;
this.entity._dirtifyLocal();
On this event, I can get the new width/height and set the other axis to match ratio wise.
The progress bar is just positioned and ‘width’ to be ratio offsets off the container (eg the max width of the progress bar is 0.X of the parent container width)
2 Likes
Nice, makes sense! That event is quite useful, thanks for letting us know.
1 Like
That’s exactly what im looking for!
Thank so much
1 Like