1. 程式人生 > >原始碼之前了無祕密之~通過原始碼學習FrameSize、WinSize、VisibleSize 3種size的區別

原始碼之前了無祕密之~通過原始碼學習FrameSize、WinSize、VisibleSize 3種size的區別

1.WinSize->CCDirector.cpp

const Size& Director::getWinSize(void) const
{
    return _winSizeInPoints;      /*看這裡返回的這個值,是在setOpenGLView中賦值的*/
}

void Director::setOpenGLView(GLView *openGLView)
{
    CCASSERT(openGLView, "opengl view should not be null");

    if (_openGLView != openGLView)
    {
        // Configuration. Gather GPU info
        Configuration *conf = Configuration::getInstance();
        conf->gatherGPUInfo();
        CCLOG("%s\n",conf->getInfo().c_str());

        if(_openGLView)
            _openGLView->release();
        _openGLView = openGLView;
        _openGLView->retain();

        // set size
        _winSizeInPoints = _openGLView->getDesignResolutionSize(); /*重點:可見winsize就是設計解析度大小*/

        _isStatusLabelUpdated = true;

        if (_openGLView)
        {
            setGLDefaultValues();
        }

        _renderer->initGLView();

        CHECK_GL_ERROR_DEBUG();

        if (_eventDispatcher)
        {
            _eventDispatcher->setEnabled(true);
        }
        
        _defaultFBO = experimental::FrameBuffer::getOrCreateDefaultFBO(_openGLView);
        _defaultFBO->retain();
    }
}

2.VisibleSize->CCGLView.cpp

Size GLView::getVisibleSize() const
{
    /*
      1.可見,visibleSize除了在NO_BORDER這種特殊情況下,其餘的也等於設計解析度大小(很容易理解:因為除了NO_BORDER情況下,其餘UI介面都是顯示完全的呀!當然可視大小就等於CocosStudio中那個畫布的大小,即設計解析度大小)
      2.可見,在非NO_BORDER情況下,winSize和VisibleSize大小是一樣的
    */
    if (_resolutionPolicy == ResolutionPolicy::NO_BORDER)  
    {
        return Size(_screenSize.width/_scaleX, _screenSize.height/_scaleY);
    }
    else 
    {
        return _designResolutionSize;
    }
}

android下視窗建立過程

3.FrameSize->CCGLView.cpp

//也就是說:最開始一單傳入完畢,那麼就固定不變了,到底width和height在那裡傳入的呢?下面以cocos2dx 3.10版本原始碼.  android系統為例子進行分析。
void GLView::setFrameSize(float width, float height)
{
    _designResolutionSize = _screenSize = Size(width, height); //setFrameSize設定的值儲存為螢幕大小了
}

//返回設定的setFrameSize大小
const Size& GLView::getFrameSize() const
{
    return _screenSize;
}

//android下面,通過android系統api,獲取到螢幕的大小.對就是螢幕的大小!!!前2個引數,是螢幕變化後的寬高,後2個是變化前的寬高
 @Override
    protected void onSizeChanged(final int pNewSurfaceWidth, final int pNewSurfaceHeight, final int pOldSurfaceWidth, final int pOldSurfaceHeight) {
        if(!this.isInEditMode()) {
            this.mCocos2dxRenderer.setScreenWidthAndHeight(pNewSurfaceWidth, pNewSurfaceHeight);
        }
    }

//根據獲得螢幕的大小,設定暫存下螢幕大小
public void setScreenWidthAndHeight(final int surfaceWidth, final int surfaceHeight) {
        this.mScreenWidth = surfaceWidth;
        this.mScreenHeight = surfaceHeight;
    }

//android通過jni呼叫cocos2dx的介面,根據android系統獲取到的螢幕寬高,傳給cocos2dx,然後設定OpenGLView視窗
@Override
    public void onSurfaceCreated(final GL10 GL10, final EGLConfig EGLConfig) {
        Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
        this.mLastTickInNanoSeconds = System.nanoTime();
        mNativeInitCompleted = true;
    }


//可見,setFrameSize在Android等系統內,是自動呼叫,傳入的大小,所以GL視窗的大小恰好等於Android手機螢幕的大小
JNIEXPORT void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    auto director = cocos2d::Director::getInstance();
    auto glview = director->getOpenGLView();
    if (!glview)
    {
        glview = cocos2d::GLViewImpl::create("Android app");
        glview->setFrameSize(w, h);  //在這傳入視窗大小了,從而啟動應用
        director->setOpenGLView(glview);

        cocos2d::Application::getInstance()->run();
    }
    else
    {
        cocos2d::GL::invalidateStateCache();
        cocos2d::GLProgramCache::getInstance()->reloadDefaultGLPrograms();
        cocos2d::DrawPrimitives::init();
        cocos2d::VolatileTextureMgr::reloadAllTextures();

        cocos2d::EventCustom recreatedEvent(EVENT_RENDERER_RECREATED);
        director->getEventDispatcher()->dispatchEvent(&recreatedEvent);
        director->setGLDefaultValues();
    }
    cocos2d::network::_preloadJavaDownloaderClass();
}

ios下視窗建立過程

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    
    
    cocos2d::Application *app = cocos2d::Application::getInstance();
    app->initGLContextAttrs();
    cocos2d::GLViewImpl::convertAttrs();
    
    // Override point for customization after application launch.
    
    // Add the view controller's view to the window and display.
    /*
	[email protected](nonatomic) CGRect            bounds;      // default bounds is zero origin, frame size. animatable
	2.可見建立的這個eaglView視窗大小也是自動傳入,等於螢幕大小.所以不要看別人bb,自己看下原始碼,一切瞭如指掌了。
    */
    window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
    CCEAGLView *eaglView = [CCEAGLView viewWithFrame: [window bounds]
                                         pixelFormat: (NSString*)cocos2d::GLViewImpl::_pixelFormat
                                         depthFormat: cocos2d::GLViewImpl::_depthFormat
                                  preserveBackbuffer: NO
                                          sharegroup: nil
                                       multiSampling: NO
                                     numberOfSamples: 0 ];
    
    [eaglView setMultipleTouchEnabled:NO];

    // Use RootViewController manage CCEAGLView
    viewController = [[RootViewController alloc] initWithNibName:nil bundle:nil];
    viewController.wantsFullScreenLayout = YES;
    viewController.view = eaglView;
    
    // Set RootViewController to window
    if ( [[UIDevice currentDevice].systemVersion floatValue] < 6.0)
    {
        // warning: addSubView doesn't work on iOS6
        [window addSubview: viewController.view];
    }
    else
    {
        // use this method on ios6
        [window setRootViewController:viewController];
    }
    
    [window makeKeyAndVisible];
    
    [[UIApplication sharedApplication] setStatusBarHidden: YES];
    
    //覆蓋安裝時第一次執行需清除遊戲快取
    std::string version = cocos2d::UserDefault::getInstance()->getStringForKey([RUN_VERSION UTF8String]);
    NSString* runVersion = [NSString stringWithUTF8String:version.c_str()];
    NSString* appVersion = [NativeInterface getVersionName];
    if(![appVersion isEqualToString:runVersion]){
        
        std::string cachePath = cocos2d::FileUtils::getInstance()->getWritablePath();
        NSString* path = [NSString stringWithUTF8String:cachePath.c_str()];
        NSFileManager *fileManager=[NSFileManager defaultManager];
        if ([fileManager fileExistsAtPath:path]) {
            NSArray *childerFiles=[fileManager subpathsAtPath:path];
            for (NSString *fileName in childerFiles) {
                NSString *absolutePath=[path stringByAppendingPathComponent:fileName];
                [fileManager removeItemAtPath:absolutePath error:nil];
            }
        }
        
        cocos2d::UserDefault::getInstance()->setStringForKey([RUN_VERSION UTF8String], [appVersion UTF8String]);
    }
    
  
    //do something 
    
    // IMPORTANT: Setting the GLView should be done after creating the RootViewController
    cocos2d::GLView *glview = cocos2d::GLViewImpl::createWithEAGLView(eaglView);
    cocos2d::Director::getInstance()->setOpenGLView(glview);
    
   
    
    app->run();  //跑起來吧...
    return YES;
}

那麼,螢幕適配策略,cocos2dx是怎麼起作用的呢?也就是setDesignResolution到底是怎麼起作用的呢?

//設定設計解析度(也就是我們看到的視窗)
void GLView::setDesignResolutionSize(float width, float height, ResolutionPolicy resolutionPolicy)
{
    CCASSERT(resolutionPolicy != ResolutionPolicy::UNKNOWN, "should set resolutionPolicy");
    
    if (width == 0.0f || height == 0.0f)
    {
        return;
    }

    _designResolutionSize.setSize(width, height);
    _resolutionPolicy = resolutionPolicy;
    
    //設定完適配策略後,生效
    updateDesignResolutionSize();
 }

//
void GLView::updateDesignResolutionSize()
{
    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) {
            _scaleX = _scaleY;
            _designResolutionSize.width = ceilf(_screenSize.width/_scaleX);
        }
        
        else if ( _resolutionPolicy == ResolutionPolicy::FIXED_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();  //重點:再次設定winSize大小,可見winSize就是設計解析度
        director->_isStatusLabelUpdated = true;
        director->setGLDefaultValues();
    }
}

-----華麗分割線-----

小結:

直接了當,上來先說結果我的理解:

FrameSize:  

螢幕實際解析度,比如:常見的手機1920 * 1080,但是你的手機尺寸可以有5寸,可以有6.44寸等。。這個FrameSize和手機尺寸大小沒有關係,是固定的值。 所看到的螢幕尺寸也許是按照這個螢幕解析度進行放縮後的結果吧。

在win上或者mac模擬器上,這個調整完後,發現彈出的框大小有變化。

WinSize:  

設計解析度,就是你在setDesignResolution中傳遞的前2個引數的值得大小。

cocosstudio中畫布的大小其實是資源解析度,如: 在棋牌中的畫布大小,1280 * 720。在傳遞setDesignResolution值的時候,傳入的設計解析度的大小未必就等於Cocostudio中資源解析度的大小,這是為了後面的計算方便。

VisibleSize:

從原始碼可以看出,除非NO_BORDER情況下,否則,visibleSize大小就是等於winSize大小。因此為了計算方便,有時候傳遞進入setDesignResolution中前2個引數的值,會根據FrameSize也就是螢幕解析度適配後,傳遞一個根據資源解析度進行放縮的一個值,然後在第三個引數中傳遞NO_BORDER,這時,VisibleSize大小恰好就是帶黑邊的整個螢幕的大小,這樣方便計算。

因此要想拉伸背景圖,那麼

local Design = {
    width = 1280,
    height = 720,
}

self.schemeSize = cc.Director:getInstance():getVisibleSize()
self.showSize = Design
-- 背景圖會進行拉伸
function AdaptationScheme:setBg(bgNode)
	if not bgNode then
		gt.log("the params bgNode is err!!!")
		return
	end
	bgNode:setScaleX(self.schemeSize.width/self.showSize.width)
	bgNode:setScaleY(self.schemeSize.height/self.showSize.height)
end

然後根據螢幕寬高比:

function AdaptationScheme:getRatio()
	return FrameSize.width/FrameSize.height
end

因此,適配的原理總結為一句話:就是根據"螢幕解析度",也就是FrameSize的寬高比的值,來決定到底採用哪種適配方式,從而決定setDesignResolution的第三個引數。其中setDesignResolution的前2個引數是設計解析度,也就是我們在CocosStudio中拼介面時,畫布的大小。

螢幕適配相關好文章:(不是特別強烈推薦!!!因為我覺得看別人分析容易誤解人,還是我上面自己分析的原始碼好撒!)

當然了,我覺得看這些文章不如看下cocos2dx原始碼來的直白,很清楚就有了自己的理解。所以原始碼之前了無祕密,有了疑惑的時候,看原始碼吧!!!

相關推薦

原始碼之前了無祕密~通過原始碼學習FrameSizeWinSizeVisibleSize 3size區別

1.WinSize->CCDirector.cpp const Size& Director::getWinSize(void) const { return _winSizeInPoints; /*看這裡返回的這個值,是在setOpenGL

Dubbo原始碼學習-通過原始碼看看dubbo對netty的使用

前言     前段時間,從頭開始將netty原始碼瞭解了個大概,但都是原理上理解。剛好博主對dubbo框架了解過一些,這次就以dubbo框架為例,詳細看看dubbo這種出色的開源框架是如何使用netty的,又是如何與框架本身邏輯進行融合的。     本文分成兩大部分,一

前端基礎學習-css文字顏色漸變的3實現

100% dom ges rgba 使用 back indent bold boot 在web前端開發過程中,UI設計師經常會設計一些帶漸變文字的設計圖,在以前我們只能用png的圖片來代替文字,今天可以實現使用純CSS實現漸變文字了。下面就介紹3中實現方式供大家參考! 基礎

android學習筆記通過java原始碼設定EditText不可編輯狀態

EditText在xml佈局檔案中,可以通過editable設定是否能夠編輯,但在實際使用中,我們可能需要動態進行設定能否進行編輯。 android:editable="true"在java原始碼中,需要通過setKeyListener(null)方法進行動態設定。 et

java集合HashMap原始碼學習

   |-- Node<K,V>[] table; // 存資料的結構 int threshold; |-- new HashMap<>() { // DEFAULT_LOAD_FACTOR = 0.75f

springMVC原始碼學習addFlashAttribute原始碼分析

本文主要從falshMap初始化,存,取,消毀來進行原始碼分析,springmvc版本4.3.18。關於使用及驗證請參考另一篇https://www.cnblogs.com/pu20065226/p/10032048.html 1.初始化和呼叫,首先是入springMVC 入口webmvc包中org.spr

rxJava和rxAndroid原始碼解析系列四subscribeOn和observeOn的理解(學習終結篇)

本篇文章主要解決subscribeOn和observeOn這兩個方法為什麼subscribeOn只有一次有效果,observeOn切換多次回撥的都有效果。 不知道朋友有沒有看過rxandroid的原始碼,如果看過的話,就會迎刃而解,沒什麼疑慮啦。沒看過原始碼的朋友,可以看看我這個系列的前幾篇文章

element-uiscrollbar原始碼解析學習

最近使用vue在做pc端專案,需要處理滾動條樣式外加滾動載入。 使用了betterscroll和perfectscroll發現前者還是更偏向於移動端(也可能我比較著急沒用明白), 後者在ie11上面拖拽滾動條的時候會閃動,會有相容性問題。 經同事點播,最終使用了element-ui裡面的scrollba

go 原始碼學習---Tail 原始碼分析

已經有兩個月沒有寫部落格了,也有好幾個月沒有看go相關的內容了,由於工作原因最近在做java以及大資料相關的內容,導致最近工作較忙,部落格停止了更新,正好想撿起之前go的東西,所以找了一個原始碼學習 這個也是之前用go寫日誌收集的時候用到的一個包 :github.com/hpcloud/tail, 這次就學

MongoDB的使用學習(七)MongoDB的聚合查詢(兩方式)附專案原始碼

@Testpublic void save() { News n = null;for (int i = 0; i < 10000; i++) { n = new News(); n.setTitle("title_" + i);

vue的原始碼學習三——原始碼構建

                                 原始碼構建    

學習《apache原始碼全景分析》DSO概念

        DSO的產生當然離不開作業系統的支援。目前不管是UNIX還是Linux,大多都提供了對動態共享物件或動態連結庫進行載入和解除安裝的機制。載入的方法通常有兩種:其一是在可執行檔案啟動時由系統程式ld.so自動載入;其二是在執行程式過程中手工通過Unix提供的動態

SpringMVC原始碼學習request處理流程 springMVC原始碼學習地址 springMVC原始碼學習addFlashAttribute原始碼分析 java reflect反射呼叫方法invoke

目的:為看原始碼提供呼叫地圖,最長呼叫邏輯深度為8層,反正我是springMVC原始碼學習地址看了兩週才理出來的。 1.處理流程(版本為4.3.18) 入口為spring-webmvc-4.3.18.RELEASE.jar中org.springframework.web.servlet.Dispatche

原始碼spring-core學習筆記

在進入原始碼筆記前,分享框架閱讀經驗:    能夠使用該框架    閱讀官方文件    瞭解該框架包結構,知道每個包的作用    原始碼可以在test中執行  

安卓開發學習LruCache原始碼閱讀

背景 LruCache是最近最久未使用的快取,是安卓系統裡常見的快取策略之一。   原始碼閱讀 LruCache類裡定義的屬性如下 private final LinkedHashMap<K, V> map; // 記憶體物件,雜湊連結串列

Netty學習旅------原始碼分析Netty執行緒本地分配機制與PooledByteBuf執行緒級物件池原理分析

final PoolArena<byte[]> heapArena; //使用輪叫輪詢機制,每個執行緒從heapArena[]中獲取一個,用於記憶體分配。 final PoolArena<ByteBuffer> directArena;

Netty學習旅----原始碼分析Netty記憶體洩漏檢測

1、圖說Netty直接記憶體管理 2、Netty 直接記憶體的使用示例 ByteBuf buf = Unpooled.directBuffer(512); System.out.println(buf); // Si

Netty netty原始碼學習大話java NIO

沉澱了一個月安安心心地學習了家純大神的Jupiter(https://github.com/fengjiachun/Jupiter),感覺受益良多,感覺自己學習了這裡面的精華的50%,不是謙虛,而是無知,因為我不知道著裡面還有多少是我沒有理解的,也許我看懂了他的程式碼,但

Android FM模組學習原始碼解析(三)

     由於最近一直忙專案,沒有時間來更新文件,今天抽空來寫一點,希望大家可以學習使用!      這一章當然還是來分析FM模組的原始碼。FmReceiver.java publicFmReceiver(String devicePath,FmRxEvCallbacks

Netty學習旅------原始碼分析Netty解碼編碼器實現原理

package io.netty.handler.codec; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandler; import io.netty.c