【cocos2d-x v3.x】
c++核心代码:
void GLView::updateDesignResolutionSize()
{
// _screenSize 就是屏幕分辨率 _designResolutionSize 传入的设计分辨率
if (_screenSize.width > 0 && _screenSize.height > 0
&& _designResolutionSize.width > 0 && _designResolutionSize.height > 0)
{
// 屏幕分辨率 与 设计分辨率的长宽比 根据适配方式取比例
_scaleX = (float)_screenSize.width / _designResolutionSize.width;
_scaleY = (float)_screenSize.height / _designResolutionSize.height;
//无黑边模式 取比值大的作为标准
if (_resolutionPolicy == ResolutionPolicy::NO_BORDER)
{
//设计分辨率不变
_scaleX = _scaleY = MAX(_scaleX, _scaleY);
}
//无截断 取比值小的
else if (_resolutionPolicy == ResolutionPolicy::SHOW_ALL)
{
//设计分辨率不变
_scaleX = _scaleY = MIN(_scaleX, _scaleY);
}
else if ( _resolutionPolicy == ResolutionPolicy::FIXED_HEIGHT) {
// 固定高度 取 height的比值 重新计算 设计分辨率的宽度
_scaleX = _scaleY;
_designResolutionSize.width = ceilf(_screenSize.width/_scaleX);
}
else if ( _resolutionPolicy == ResolutionPolicy::FIXED_WIDTH) {
// 固定宽度 取 width的比值 重新计算 设计分辨率的高度
_scaleY = _scaleX;
_designResolutionSize.height = ceilf(_screenSize.height/_scaleY);
}
// calculate the rect of viewport
float viewPortW = _designResolutionSize.width * _scaleX;
float viewPortH = _designResolutionSize.height * _scaleY;
_viewPortRect.setRect((_screenSize.width - viewPortW) / 2, (_screenSize.height - viewPortH) / 2, viewPortW, viewPortH);
// reset director's member variables to fit visible rect
auto director = Director::getInstance();
director->_winSizeInPoints = getDesignResolutionSize();
director->_isStatusLabelUpdated = true;
director->setProjection(director->getProjection());
glViewport(0, 0, _screenSize.width, _screenSize.height);
}
}
总结:
frameSize ======> 设备实际分辨率(1280*720 ,2340*1080),实际的屏幕大小。( 可以根据这个尺寸选择适配方式 )
CCSize winSize = CCDirector::sharedDirector()->getWinSize();
const Size& Director::getWinSize(void) const
{
return _winSizeInPoints;
}
_winSizeInPoints = _openGLView->getDesignResolutionSize();
winSize =======> 显示窗口分辨率, 是通过计算后的设计分辨率,(UI元素的显示逻辑 根据这个分辨率适配)
visibleSize 任何情况下 visibleSize == WinSize。
_viewPortRect:视图viewPort,这个分辨率与最终的_designResolutionSize成比例
float viewPortW = _designResolutionSize.width * _scaleX;
float viewPortH = _designResolutionSize.height * _scaleY;
【cocoscreator 2.x】(跟2dx的逻辑基本一致)
1、CCCanvas.js
//修改canvas size个pos
alignWithScreen: function () {
var designSize, nodeSize;
if (CC_EDITOR) {
nodeSize = designSize = cc.engine.getDesignResolutionSize();
this.node.setPosition(designSize.width * 0.5, designSize.height * 0.5);
}
else {
//这里取得最终的visibleRect
var canvasSize = nodeSize = cc.visibleRect;
designSize = cc.view.getDesignResolutionSize();
var clipTopRight = !this.fitHeight && !this.fitWidth;
var offsetX = 0;
var offsetY = 0;
if (clipTopRight) {
// offset the canvas to make it in the center of screen
offsetX = (designSize.width - canvasSize.width) * 0.5;
offsetY = (designSize.height - canvasSize.height) * 0.5;
}
this.node.setPosition(canvasSize.width * 0.5 + offsetX, canvasSize.height * 0.5 + offsetY);
}
this.node.width = nodeSize.width;
this.node.height = nodeSize.height;
},
//设置canvas的fixed方式
applySettings: function () {
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) {
policy = ResolutionPolicy.FIXED_WIDTH;
}
else { // fitHeight
policy = ResolutionPolicy.FIXED_HEIGHT;
}
var designRes = this._designResolution;
if (CC_EDITOR) {
cc.engine.setDesignResolutionSize(designRes.width, designRes.height);
}
else {
cc.view.setDesignResolutionSize(designRes.width, designRes.height, policy);
}
}
2.CCView.js
setDesignResolutionSize: function (width, height, resolutionPolicy) {
this.setResolutionPolicy(resolutionPolicy);
var policy = this._resolutionPolicy;
this._originalDesignResolutionSize.width = this._designResolutionSize.width = width;
this._originalDesignResolutionSize.height = this._designResolutionSize.height = height;
//关键代码
var result = policy.apply(this, this._designResolutionSize);
if(result.scale && result.scale.length === 2){
this._scaleX = result.scale[0];
this._scaleY = result.scale[1];
}
// 关键数据 result 在fixedWidth或者fixedHeight其一时
//viewPort = 原framesize(用于计算设计后的分辨率)其他情况下viewport是经过计算的
if(result.viewport){
var vp = this._viewportRect,
vb = this._visibleRect,
rv = result.viewport;
vp.x = rv.x;
vp.y = rv.y;
vp.width = rv.width;
vp.height = rv.height;
vb.x = 0;
vb.y = 0;
vb.width = rv.width / this._scaleX;
vb.height = rv.height / this._scaleY;
}
policy.postApply(this);
cc.winSize.width = this._visibleRect.width;
cc.winSize.height = this._visibleRect.height;
//visibleRect = 最终被canvas使用的尺寸
cc.visibleRect && cc.visibleRect.init(this._visibleRect);
renderer.updateCameraViewport();
_cc.inputManager._updateCanvasBoundingRect();
this.emit('design-resolution-changed');
},
计算 result的代码
_buildResult: function (containerW, containerH, contentW, contentH, scaleX, scaleY) {
// Makes content fit better the canvas
Math.abs(containerW - contentW) < 2 && (contentW = containerW);
Math.abs(containerH - contentH) < 2 && (contentH = containerH);
//主要是后两个值。可以理解为经过适配后的设计分辨率
var viewport = cc.rect((containerW - contentW) / 2, (containerH - contentH) / 2, contentW, contentH);
// Translate the content
if (cc.game.renderType === cc.game.RENDER_TYPE_CANVAS){
//TODO: modify something for setTransform
//cc.game._renderContext.translate(viewport.x, viewport.y + contentH);
}
this._result.scale = [scaleX, scaleY];
this._result.viewport = viewport;
return this._result;
},
_buildResult实际传入的数据由各种适配方式决定
比如 fixedWidth
var FixedWidth = cc.Class({
name: "FixedWidth",
extends: cc.ContentStrategy,
apply: function (view, designedResolution) {
var containerW = cc.game.canvas.width, containerH = cc.game.canvas.height,
designW = designedResolution.width, scale = containerW / designW,
contentW = containerW, contentH = containerH;
//contentW 和 contentH都是原值传入的
return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
}
});
再如
var ShowAll = cc.Class({
name: "ShowAll",
extends: cc.ContentStrategy,
apply: function (view, designedResolution) {
var containerW = cc.game.canvas.width, containerH = cc.game.canvas.height,
designW = designedResolution.width, designH = designedResolution.height,
scaleX = containerW / designW, scaleY = containerH / designH, scale = 0,
contentW, contentH;
scaleX < scaleY ? (scale = scaleX, contentW = containerW, contentH = designH * scale)
: (scale = scaleY, contentW = designW * scale, contentH = containerH);
//contentW 和 contentH是经过缩放的
return this._buildResult(containerW, containerH, contentW, contentH, scale, scale);
}
});
总结:关键概念,1. viewportRect(最终可视裁剪区域:它决定最终的显示区域,最终的设计分辨率通过缩放显示在此分辨率下),接口cc.view.getViewportRect()获得;
viewportRect:在fixedHeight或者fixedWidth都等于frameSize;在其他情况由frameSize与designedResolution的比例决定. viewPortRect.height = designH*scale
2. _visibleRect 适配策略后到设计分辨率
除了FixedWidth或FixedHeight 会有变化,其他情况都得到的是canvas设计分辨率,
cc.winSize和cc.view.getVisibleSize()的返回值是一样的 都是visibleRect;
cc.view.getDesignResolutionSize()和cc.view.getFrameSize()决定适配方式。设计分辨率到屏幕的显示 可以用cc.view.getViewportRect()()来理解
3. cc.view._scaleX scaleY 缩放比例,除了ExactFit俩值不一样,其他都一样。可视裁剪viewportRect与设计分辨率designedResolution的缩放比例;从这里可以预制显示区域的大小。
过程:_scaleX,Y 决定viewport的大小。viewport / _scalex,y决定final designedResolution即_visibleRect。