屏幕适配文档
cocos creator 适配方案:https://docs.cocos.com/creator/manual/zh/ui/multi-resolution.html
设计分辨率
设计分辨率一般使用1334*750的尺寸 宽高比为1.778
我的解决方案
- 根据屏幕分辨率与设计分辨率的宽高比的不同动态选择fit_height 还是 fit_width,这需要修改引擎源码
applySettings: function () {
var frameSize = cc.view.getFrameSize();
var designRes = this._designResolution;
var oldRatio = frameSize.width/frameSize.height;
var newRatio = designRes.width/designRes.height;
cc.log('newRatio ',newRatio,' oldRatio ',oldRatio)
cc.log('frameSize ',frameSize,' designRes ',designRes)
var ResolutionPolicy = cc.ResolutionPolicy;
var policy;
if (this.fitHeight && this.fitWidth) {
policy = ResolutionPolicy.SHOW_ALL;
}
else if (!this.fitHeight && !this.fitWidth) {
policy = ResolutionPolicy.NO_BORDER;
}
else if (this.fitWidth) {
if(newRatio < oldRatio){
policy = ResolutionPolicy.FIXED_HEIGHT;
}else{
policy = ResolutionPolicy.FIXED_WIDTH;
}
}
else if (this.fitHeight) {// fitHeight
if(newRatio < oldRatio){
policy = ResolutionPolicy.FIXED_WIDTH;
}else{
policy = ResolutionPolicy.FIXED_HEIGHT;
}
}
if (CC_EDITOR) {
cc.engine.setDesignResolutionSize(designRes.width, designRes.height);
}
else {
cc.view.setDesignResolutionSize(designRes.width, designRes.height, policy);
}
}
删除ide的缓存文件重新启动。
非必要的情况下我不会去改动源码,因为升级成本太高,但是引擎在第一次启动后走这里之后你再设置适配策略就不好使了,所以只能这里修改。具体原因可以参看源码。
updateCameraViewport () {
// TODO: remove HACK
if (!CC_EDITOR && cc.director) {
let ecScene = cc.director.getScene();
if (ecScene) ecScene.setScale(1, 1, 1);
}
//如果是canvas模式才会走下边的代码。
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS) {
let vp = cc.view.getViewportRect();
this.device.setViewport(vp.x, vp.y, vp.width, vp.height);
this._camera.a = cc.view.getScaleX();
this._camera.d = cc.view.getScaleY();
this._camera.tx = vp.x;
this._camera.ty = vp.y + vp.height;
}
},
使用widget 适配ui 将ui上的控件添加widget组件,为了使widget生效,注意全屏的控件都要添加widget,并且四个方向都设置为0.
使用设计分辨率和显示分辨率的宽宽比或者高高比缩放背景图。
const { ccclass, property } = cc._decorator;
@ccclass
export default class AdaptBg extends cc.Component {
start() {
let designSize = cc.Canvas.instance.designResolution;
let visibleSize = cc.view.getVisibleSize()
let rw = visibleSize.width / designSize.width
let rh = visibleSize.height / designSize.height;
let bgRatio = 1;
if (rw > rh) {
bgRatio = rw;
} else {
bgRatio = rh;
}
// this.node为背景图片
this.node.scale = bgRatio
}
}
- 刘海屏的适配 根据屏幕分辨率和设计分辨率的比求出需要顶部内容或者左边内容需要移动的高度或者宽度。因为我们没办法知道哪些是刘海屏,哪些不是,所以做了统一处理。这种思想其实出自一个年轻帅气又上进的小伙子。我感觉比那些直接设置canvas宽高的方式要好很多。
export enum OrientationType {
Portrait,
Landscape,
};
const AdaptTarget = cc.Enum({
None: 0,
AdaptPosForTopBang: 1, //针对顶部刘海,适配元素位置,通过调整Widget属性(竖屏往下移,左横屏往右移)
AdaptPosForBottomBar: 2, //针对底部横条,适配元素位置,通过调整Widget属性(竖屏往上移,左横屏往左移)
AdaptSizeForTopBang: 3, //针对顶部刘海,适配元素大小,(竖屏往下拉高,左横屏往右拉宽)
AdaptSizeForBottomBar: 4, //针对底部横条,适配元素大小,(竖屏往上拉高,左横屏往左拉宽)
});
export enum FitType {
HEIGHT,
WIDTH,
}
const { ccclass, property } = cc._decorator;
@ccclass
export default class AdaptUI extends cc.Component {
@property({
type: AdaptTarget
})
target = AdaptTarget.AdaptPosForTopBang;
private widget: cc.Widget;
start() {
this.widget = this.node.getComponent(cc.Widget);
if (!this.widget) {
this.widget = this.node.addComponent(cc.Widget);
}
let frameSize = cc.view.getFrameSize();
let frameAspectRatio = frameSize.width / frameSize.height;
let designSize = cc.Canvas.instance.designResolution;
let designAspectRatio = designSize.width / designSize.height
let deltaAspectRatio = 1 / (frameAspectRatio - designAspectRatio);
console.log("deltaAspectRatio ", deltaAspectRatio);
let topOffset = 0;
if (topOffset === 0 && deltaAspectRatio > 0) {
topOffset = deltaAspectRatio * 120;//这个值根据自己的设计分辨率调整
}
let bottomOffset = 0;
if (bottomOffset === 0 && deltaAspectRatio > 0) {
bottomOffset = deltaAspectRatio * 100;
}
let orientation = designSize.height > designSize.width ? OrientationType.Portrait : OrientationType.Landscape;
this.adaptLogic(topOffset, bottomOffset, orientation);
}
adaptLogic(topOffset, bottomOffset, orientation) {
switch (this.target) {
case AdaptTarget.AdaptPosForTopBang:
if (topOffset == 0) { return; }
switch (orientation) {
case OrientationType.Portrait:
this.widget.top += topOffset;
break;
case OrientationType.Landscape:
this.widget.left += topOffset;
break;
}
break;
case AdaptTarget.AdaptPosForBottomBar:
if (bottomOffset == 0) { return; }
switch (orientation) {
case OrientationType.Portrait:
this.widget.bottom += bottomOffset;
break;
case OrientationType.Landscape:
this.widget.right += bottomOffset;
break;
}
break;
case AdaptTarget.AdaptSizeForTopBang:
if (topOffset == 0) { return; }
switch (orientation) {
case OrientationType.Portrait:
this.node.anchorY = 1;
this.node.height += topOffset;
break;
case OrientationType.Landscape:
this.node.anchorX = 0;
this.node.width += topOffset;
break;
}
break;
case AdaptTarget.AdaptSizeForBottomBar:
if (bottomOffset == 0) { return; }
switch (orientation) {
case OrientationType.Portrait:
this.node.anchorY = 0;
this.node.height += bottomOffset;
break;
case OrientationType.Landscape:
this.node.anchorX = 1;
this.node.width += bottomOffset;
break;
}
break;
}
}
}
结语
以上是我个人使用的方式,仅供参考,如有疑问可以在下方留言。
欢迎关注公众号《微笑游戏》,浏览更多内容。
更多内容
跨引擎游戏开发框架
小游戏SDK整合框架
使用四叉树优化碰撞检
游戏开发中UI管理器的使用
小游戏开发中如何优雅的使用本地存档
sdk接入整合,用一个变量切换不同渠道
CocosCreator之AssetBundle使用方案分享
CocosCreator之填色游戏的一种实现方案
一个可屏蔽长短链接的网络模块
游戏开发中的人工智能