大部分竖屏快游戏都很少有兼顾宽屏分辨率的情况,Laya 游戏会有一个自动横屏的机制,会将整个画面横向显示,而像 CC 游戏,基本都是 UI 位置大小严重失调,要么导致某些区域点不了,要么导致 UI 飞出屏幕外,根本看不到点不着。针对这两个常见的游戏框架做了一个竖屏适配修复,可以用修复代码在启动阶段将游戏画面按设定好的比例强制自适配调整。推荐比例:9:16、10:16、9:20。
fixPortrait() {
if (window.cc) {
_fixCCPortrait();
} else if (Laya) {
_fixLayaPortrait();
}
}
_fixLayaPortrait() {
if (!Laya) return;
const bestRatio = window.sdkConfig?.bestRatio;
let maxRatio = 9 / 20;
if (bestRatio) {
const [w, h] = bestRatio.split(':').map(Number);
maxRatio = w / h;
}
Laya._stage = Laya.stage;
Object.defineProperty(Laya, 'stage', {
set: function(val) {
Laya._stage = val;
const setScreenSize = val.setScreenSize;
let _rawWidth = 0;
let _rawHeight = 0;
val.setScreenSize = function(width, height) {
const pixelRatio = Laya.Browser.pixelRatio;
let rawWidth = width / pixelRatio;
let rawHeight = height / pixelRatio;
if (rawWidth / rawHeight > maxRatio) {
rawWidth = rawHeight * maxRatio;
width = rawWidth * pixelRatio;
height = rawHeight * pixelRatio;
}
_rawWidth = rawWidth;
_rawHeight = rawHeight;
setScreenSize.apply(val, [width, height]);
};
const identity = val._canvasTransform.identity;
val._canvasTransform.identity = function(...args) {
identity.apply(val._canvasTransform, args);
val._canvasTransform.tx = (Laya.Browser.clientWidth - _rawWidth) / 2;
return val._canvasTransform;
};
const scale = val._canvasTransform.scale;
val._canvasTransform.scale = function(...args) {
scale.apply(val._canvasTransform, args);
val._canvasTransform.tx = (Laya.Browser.clientWidth - _rawWidth) / 2;
return val._canvasTransform;
};
},
get: function() {
return Laya._stage;
},
configurable: true,
enumerable: true,
});
}
_fixCCPortrait() {
const cc = window.cc;
const view = cc?.view;
const canvas = cc?.game?.canvas;
if (!view || !canvas) return;
const bestRatio = window.sdkConfig?.bestRatio;
let maxRatio = 9 / 20;
if (bestRatio) {
const [w, h] = bestRatio.split(':').map(Number);
maxRatio = w / h;
}
const getViewport = (width?: number, height?: number) => {
const viewportWidth = width || window.innerWidth || document.documentElement.clientWidth;
const viewportHeight = height || window.innerHeight || document.documentElement.clientHeight;
return {
width: Math.max(1, viewportWidth),
height: Math.max(1, viewportHeight),
};
};
const applyViewportStyle = (viewportWidth?: number, viewportHeight?: number) => {
const viewport = getViewport(viewportWidth, viewportHeight);
const width = Math.min(viewport.width, viewport.height * maxRatio);
const height = viewport.height;
if (view._frameSize) {
view._frameSize.width = width;
view._frameSize.height = height;
}
if (canvas.style) {
canvas.style.position = "fixed";
canvas.style.left = `${Math.round((viewport.width - width) / 2)}px`;
canvas.style.top = "0px";
canvas.style.width = `${Math.round(width)}px`;
canvas.style.height = `${Math.round(height)}px`;
canvas.style.margin = "0px";
}
};
const initFrameSize = view._initFrameSize;
view._initFrameSize = function() {
initFrameSize.apply(this, arguments);
applyViewportStyle();
};
const setDesignResolutionSize = view.setDesignResolutionSize;
view.setDesignResolutionSize = function() {
const result = setDesignResolutionSize.apply(this, arguments);
applyViewportStyle();
return result;
};
const setCanvasSize = view.setCanvasSize;
if (typeof setCanvasSize === "function") {
view.setCanvasSize = function(width: number, height: number) {
const viewport = getViewport(width, height);
const result = setCanvasSize.call(this, viewport.width, viewport.height);
applyViewportStyle(viewport.width, viewport.height);
return result;
};
}
const refreshResolution = () => {
applyViewportStyle();
const resolution = view._originalDesignResolutionSize || view._designResolutionSize;
if (!resolution || resolution.width <= 0 || resolution.height <= 0) return;
view.setDesignResolutionSize(
resolution.width,
resolution.height,
view._resolutionPolicy,
);
};
window.addEventListener("resize", refreshResolution);
window.addEventListener("orientationchange", refreshResolution);
this.onWindowResize(refreshResolution);
if (typeof view._resizeEvent === "function") {
view._resizeEvent(true);
} else {
refreshResolution();
}
}