亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 系統 > Android > 正文

Cocos2d-x入門教程(詳細的實例和講解)

2020-04-11 11:50:44
字體:
來源:轉載
供稿:網友

智能終端上的游戲目前風頭正勁,試問哪個智能手機上沒有幾款企鵝公司出品的游戲呢!之前從未涉獵過游戲開發,但知道游戲開發前要挑選一款合適的游戲引擎,自己從頭開始敲代碼的時代已經out了。在尋覓游戲引擎之前,我需要回答三道擺在我面前的選擇題:

    1、2D引擎還是3D引擎?
    2、平臺專用引擎還是跨平臺引擎?
    3、收費引擎還是開源引擎?

作為入門級選手,2D游戲顯然更適合上手一些,另外適合果果這個年齡段的幼教類的游戲也多以2D游戲居多。3D游戲本身也太難了,不僅要 Programming能力,還要3D建模能力,這些學習起來周期就太長了;一直是Ubuntu Fans,手頭沒有Mac Book,這樣開發iOS程序變成一件糟心的事,在Ubuntu下搭建iOS App開發環境繁雜的很,即便是虛擬機也懶得嘗試。但從游戲體驗來看,還是在iPad上玩更好一些,因此最好引擎能跨平臺,以便后續遷移到iOS上;開源 和用開源慣了,收費的引擎目前不在考慮范圍之內。綜上,我要尋找的是一款開源的、跨平臺的Mobile 2D Game Engine。

于是我找到了Cocos2d-x!Cocos2d-x是Cocos2d-iphone的C++跨平臺分支,由于是國人創立的,在國內有著較大的用 戶群,引擎資料也較多,社區十分活躍。國內已經出版了多本有關Cocos2d-x的中文書籍,比如《Cocos2d-x高級開發教程:制作自己的 “捕魚達人”》 、《Cocos2d-x權威指南》 等都還不錯。更重要的是Cocos2d-x自帶了豐富的例子,供初學者“臨摹學習”,其中cocos2d-x-2.2.2/samples/Cpp /TestCpp這個例子幾乎涵蓋了該引擎的絕大多數功能。下面就開啟Cocos2d-x的入門之旅(For Android)。

一、引擎安裝

試驗環境:

復制代碼 代碼如下:
   Ubuntu 12.04.1 x86_64
   gcc 4.6.3
   javac 1.7.0_21
   java "1.7.0_21" HotSpot 64-bit Server VM
   adt-bundle-linux-x86_64-20131030.zip
   android-ndk-r9d-linux-x86_64.tar.bz2
 

Cocos2d-x官網目前提供2.2.2穩定版以及3.0beta2版的下載(當然你也可以下載到更老的版本)。由于3.0改變較大,資料不 多,且對編譯器等版本的要求較高(需要支持C++ 11標準),因此這里依舊以2.2.2版本作為學習目標。Cocos2d-x-2.2.2下載后解壓到某個目錄:比如/home1/tonybai/android-dev/cocos2d-x-2.2.2。 如果僅是用Cocos2d-x開發Android版本游戲,則不需要做什么編譯工作。Android Game Project會在Project build時自動用NDK的編譯器編譯C++代碼,并與NDK鏈接。如果你想早點看看Cocos2d-x sample中的例子運行起來到底是什么樣子的,你可以在Ubuntu下編譯出Linux版本的游戲:在cocos2d-x-2.2.2下執行make-all-linux-project.sh即可。編譯需要一段時間,編譯成 功后,我們可以進入到“cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.linux/bin/release” 下執行“HelloCpp”這個可執行文件,一個最簡單的Cocos2d-x游戲就會展現在你的面前了。

Android sample project的構建稍微復雜些:

首先在Eclipse中添加libcocos2dx Library project from existed code(注意:不Copy到workspace,原地建立)。該Project的代碼路徑為cocos2d-x-2.2.2/cocos2dx/platform /android/java。在project.properties和AndroidManifest.xml適當修改你所使用的api版本, 以讓編譯通過。我這里用的是 target=android-19。

然后,設置NDK_ROOT環境變量(比如export NDK_ROOT='/home1/tonybai/android-dev/adt-bundle-linux-x86_64/android-ndk-r9c'), 供build_native.sh使用。

最后添加游戲project。在Eclipse中添加HelloCpp project from existed code,位置cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android(注 意:不Copy到Workspace中,原地建立)。在HelloCpp的project.properties中添加“android.library.reference.1=../../../../cocos2dx/platform/android /java”。同樣別忘了在project.properties和AndroidManifest.xml適當修改你所使用 的api版本,以讓編譯通過。

如果一切順利的話,你會在Console窗口看到“**** Build Finished ****”。Problems窗口顯示“0 errors“。 啟動Android模擬器,Run Application,同樣的HelloCpp畫面會呈現在模擬器上。

Cocos2d-x是建構在OpenGL技術之上的。對于Android平臺而言,Android SDK已經完全封裝了opengl es 1.1/2.0的API(android.opengl.*;javax.microedition.khronos.egl.*;javax.microedition.khronos.opengles.*), 引擎完全可以建立在這個之上,無需C++代碼。但Cocos2d-x是一個跨平臺的2D游戲引擎,核心選擇了用C++代碼實現(iOS提供的C綁 定,不提供Java綁定;Android則提供了Java和C綁定),因此 在開發Android平臺的2D游戲時,引擎部分是SDK與NDK交相互應,比如GLThread的創建和管理用的是SDK的 GLSurfaceView和GLThread,但真正的Surface繪制部分則是回調Cocos2d-x用C++編寫的繪制實現(鏈接NDK 中的庫)。

二、Cocos2d-x Android工程代碼組織結構

以samples/Cpp/HelloApp的Android工程為例,Android版的Cocos2d-x工程與普通android應用程序 差別 不大,核心部分只是多了一個jni目錄和一個build_native.sh腳本文件。其中jni目錄下存放的是Java和C++調用轉換的“膠 水”代碼;build_native.sh則是用于編譯jni下C++代碼以及 cocos2dx_static library代碼的構建腳本。

HelloCpp的構建過程摘要如下:

復制代碼 代碼如下:

**** Build of configuration Default for project HelloCpp ****

bash /home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/build_native.sh
NDK_ROOT = /home1/tonybai/android-dev/adt-bundle-linux-x86_64/android-ndk-r9c
COCOS2DX_ROOT = /home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/../../../..
APP_ROOT = /home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/..
APP_ANDROID_ROOT = /home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android
+ /home1/tonybai/android-dev/adt-bundle-linux-x86_64/android-ndk-r9c/ndk-build -C /home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.androidNDK_MODULE_PATH=/home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/../../../..:/home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/../../../../cocos2dx/platform/third_party/android/prebuilt
Using prebuilt externals
Android NDK: WARNING:/home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/../../../../cocos2dx/Android.mk:cocos2dx_static: LOCAL_LDLIBS is always ignored for static libraries 
make: Entering directory `/home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android'
[armeabi] Compile++ thumb: hellocpp_shared <= main.cpp
[armeabi] Compile++ thumb: hellocpp_shared <= AppDelegate.cpp
[armeabi] Compile++ thumb: hellocpp_shared <= HelloWorldScene.cpp
[armeabi] Compile++ thumb: cocos2dx_static <= CCConfiguration.cpp
[armeabi] Compile++ thumb: cocos2dx_static <= CCScheduler.cpp
 … …
[armeabi] Compile++ thumb: cocos2dx_static <= CCTouch.cpp
[armeabi] StaticLibrary  : libcocos2d.a
[armeabi] Compile thumb  : cpufeatures <= cpu-features.c
[armeabi] StaticLibrary  : libcpufeatures.a
[armeabi] SharedLibrary  : libhellocpp.so
[armeabi] Install        : libhellocpp.so => libs/armeabi/libhellocpp.so
make: Leaving directory `/home1/tonybai/android-dev/cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android'

**** Build Finished ****


指揮NDK編譯的則是jni下的Android.mk文件,其角色類似于Makefile。

三、Cocos2d-x Android工程代碼閱讀

單獨將如何閱讀代碼拿出來,是為了后面分析引擎的驅動流程做準備工作。學習類似Cocos2d-x這樣的游戲引擎,僅僅停留在游戲邏輯層代碼是不 能很好的把握引擎本質的,因此適當的挖掘引擎實現實際上對于理解和使用 引擎都是大有裨益的。

以一個Cocos2d-x Android工程為例,它的游戲邏輯代碼以及涉及的引擎代碼涵蓋在一下路徑下(還是以HelloCpp的Android工程為例):

復制代碼 代碼如下:

    項目層:
        * cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/src  主Activity的實現;
        * cocos2d-x-2.2.2/samples/Cpp/HelloCpp/proj.android/jni/hellocpp  Cocos2dxRenderer類的nativeInit實現,用于引出Application的入口;
        * cocos2d-x-2.2.2/samples/Cpp/HelloCpp/Classes 你的游戲邏輯,以C++代碼形式呈現;

    引擎層:
        * cocos2d-x-2.2.2/cocos2dx/platform/android/java/src 引擎層對Android Activity、GLSurfaceView以及Render的封裝
        * cocos2d-x-2.2.2/cocos2dx/platform/android/jni 對應上面封裝的native method實現
        * cocos2d-x-2.2.2/cocos2dx、cocos2d-x-2.2.2/cocos2dx/platform、cocos2d-x- 2.2.2/cocos2dx/platform/android   cocos2dx引擎的核心實現(針對android平臺)

后續的代碼分析也將從這兩個層次、六處位置出發。

四、從Activity開始

之前多少了解了一些Android App開發的知識,Android App都是始于Activity的。游戲也是App的一種,因此在Android平臺上,Cocos2d-x游戲也是從Activity開始的。于是 Activity,確切的說是Cocos2dxActivity是我們這次引擎驅動機制分析的出發點。

回顧Android Activity的Lifecycle,Activity啟動的順序是:Activity.onCreate -> Activity.onStart() -> Activity.onResume()。接下來我們將按照 這條主線進行引擎驅動機制的分析。

HelloCpp.java中的HelloCpp這個Activity完全無所作為,僅僅是繼承其父類Cocos2dxActivity的實現罷 了。

復制代碼 代碼如下:

// HelloCpp.java
public class HelloCpp extends Cocos2dxActivity{
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
    }
    … …
}

我們來看Cocos2dxActivity類。
復制代碼 代碼如下:

// Cocos2dxActivity.java

@Override
protected void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    sContext = this;
    this.mHandler = new Cocos2dxHandler(this);
    this.init();
    Cocos2dxHelper.init(this, this);
}

public void init() {
        // FrameLayout
        ViewGroup.LayoutParams framelayout_params =
            new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT,
                                       ViewGroup.LayoutParams.FILL_PARENT);
        FrameLayout framelayout = new FrameLayout(this);
        framelayout.setLayoutParams(framelayout_params);

        … …
        // Cocos2dxGLSurfaceView
        this.mGLSurfaceView = this.onCreateView();

        // …add to FrameLayout
        framelayout.addView(this.mGLSurfaceView);
        … …
        this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());
        … …

        // Set framelayout as the content view
        setContentView(framelayout);
}

從上面代碼可以看出,onCreate調用的init方法才是Cocos2dxActivity初始化的核心。在init方法 中,Cocos2dxActivity創建了一個Framelayout實例,并將該實例作為content View賦給了Cocos2dxActivity的實例。Framelayout實例也并不孤單,一個設置了Cocos2dxRenderer實例的 GLSurfaceView被Added to it。而Cocos2d-x引擎的初始化已經悄悄地在這幾行代碼間完成了,至于初始化的細節我們后續再做分析。

接下來是onResume方法,它的實現如下:

復制代碼 代碼如下:

    @Override
    protected void onResume() {
        super.onResume();

        Cocos2dxHelper.onResume();
        this.mGLSurfaceView.onResume();
    }


onResume調用了View的onResume()。
復制代碼 代碼如下:

// Cocos2dxGLSurfaceView:
    @Override
    public void onResume() {
        super.onResume();

        this.queueEvent(new Runnable() {
            @Override
            public void run() {
                Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleOnResume();
            }
        });
    }


Cocos2dxGLSurfaceView將該事件打包放到隊列里,扔給了另外一個線程去執行(后續會詳細說明這個線程),對應的方法在 Cocos2dxRenderer class中。
復制代碼 代碼如下:

    public void handleOnResume() {
        Cocos2dxRenderer.nativeOnResume();
    }

Render實際上調用的是native方法。
復制代碼 代碼如下:

 JNIEXPORT void JNICALL Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeOnResume() {
        if (CCDirector::sharedDirector()->getOpenGLView()) {
            CCApplication::sharedApplication()->applicationWillEnterForeground();
        }
    }

applicationWillEnterForeground方法在你的AppDelegate.cpp中;

void AppDelegate::applicationWillEnterForeground() {
    CCDirector::sharedDirector()->startAnimation();//

    // if you use SimpleAudioEngine, it must resume here
    // SimpleAudioEngine::sharedEngine()->resumeBackgroundMusic();
}

這里僅是重新獲得了一下時間罷了。

五、Render Thread(渲染線程) - GLThread

游戲引擎要兼顧UI事件和屏幕幀刷新。Android的OpenGL應用采用了UI線程(Main Thread) +  渲染線程(Render Thread)的模式。Activity活在Main Thread(主線程)中,也叫做UI線程。該線程負責捕獲與用戶交互的信息和事件,并與渲染(Render)線程交互。比如當用戶接聽電話、切換到其他 程序時,渲染線程必須知道發生了 這些事件,并作出即時的處理,而這些事件及處理方式都是由主線程中的Activity以及其裝載的View傳遞給渲染線程的。我們在Cocos2dx的框 架代碼中看不到渲染線程的誕生過程,這是因為這一過程是在Android SDK層實現的。

我們回顧一下Cocos2dxActivity.init方法的關鍵代碼:

復制代碼 代碼如下:

    // Cocos2dxGLSurfaceView
    this.mGLSurfaceView = this.onCreateView();

    // …add to FrameLayout
    framelayout.addView(this.mGLSurfaceView);
    this.mGLSurfaceView.setCocos2dxRenderer(new Cocos2dxRenderer());

    // Set framelayout as the content view
    setContentView(framelayout);

Cocos2dxGLSurfaceView是 android.opengl.GLSurfaceView的子類。在android 上做原生opengl es 2.0編程的人應該都清楚GLSurfaceView的重要性。但渲染線程并非是在Cocos2dxGLSurfaceView實例化時被創建的,而是在 setRenderer的時候。

我們來看Cocos2dxGLSurfaceView.setCocos2dxRenderer的實現:

復制代碼 代碼如下:

    public void setCocos2dxRenderer(final Cocos2dxRenderer renderer) {
        this.mCocos2dxRenderer = renderer;
        this.setRenderer(this.mCocos2dxRenderer);
    }

setRender是Cocos2dxGLSurfaceView父類GLSurfaceView實現的方法。在Android SDK GLSurfaceView.java文件中,我們看到:
復制代碼 代碼如下:

       public void setRenderer(Renderer renderer) {
        checkRenderThreadState();
        if (mEGLConfigChooser == null) {
            mEGLConfigChooser = new SimpleEGLConfigChooser(true);
        }
        if (mEGLContextFactory == null) {
            mEGLContextFactory = new DefaultContextFactory();
        }
        if (mEGLWindowSurfaceFactory == null) {
            mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
        }
        mRenderer = renderer;
        mGLThread = new GLThread(mThisWeakRef);
        mGLThread.start();
    }

GLThread的實例是在這里被創建并開始執行的。至于渲染線程都干了些什么,我們可以通過其run方法看到:

復制代碼 代碼如下:

        @Override
        public void run() {
            setName("GLThread " + getId());
            if (LOG_THREADS) {
                Log.i("GLThread", "starting tid=" + getId());
            }

            try {
                guardedRun();
            } catch (InterruptedException e) {
                // fall thru and exit normally
            } finally {
                sGLThreadManager.threadExiting(this);
            }
        }

run方法并沒有給我們帶來太多有價值的東西,真正有價值的信息藏在guardedRun方法中。guardedRun是這個源文件中規模最為龐 大的方法,但抽取其核心結構后,我們發現它大致就是一個死循環,以下是摘要式的偽代碼:

復制代碼 代碼如下:

while (true) {
   synchronized (sGLThreadManager) {
       while (true) {
           …. …
           if (! mEventQueue.isEmpty()) {
               event = mEventQueue.remove(0);
               break;
           }
        } 
   }//end of synchronized (sGLThreadManager)

    if (event != null) {
       event.run();
       event = null;
       continue;
   } 

   if needed
       view.mRenderer.onSurfaceCreated(gl, mEglHelper.mEglConfig);

   if needed
       view.mRenderer.onSurfaceChanged(gl, w, h);

   if needed
       view.mRenderer.onDrawFrame(gl);
}


在這里我們看到了event、Renderer的三個回調方法onSurfaceCreated、onSurfaceChanged以及 onDrawFrame,后續我們會對這三個函數做詳細分析的。

六、游戲邏輯的入口

在HelloCpp的Classes下有好多C++代碼文件(涉及具體的游戲邏輯),在HelloCpp的android project jni目錄下也有Jni膠水代碼,那么這些代碼是如何和引擎一起互動生效的呢?

上面講到過,涉及到畫面的一些渲染都是在GLThread中進行的,這涉及到onSurfaceCreated、 onSurfaceChanged以及onDrawFrame三個方法。我們看看 Cocos2dxRenderer.onSurfaceCreated方法的實現,該方法會在Surface被首次渲染時調用:

復制代碼 代碼如下:

    public void onSurfaceCreated(final GL10 pGL10, final EGLConfig pEGLConfig) {
        Cocos2dxRenderer.nativeInit(this.mScreenWidth, this.mScreenHeight);
        this.mLastTickInNanoSeconds = System.nanoTime();
    }

該方法繼續調用HelloCpp工程jni目錄下的nativeInit代碼:
復制代碼 代碼如下:

void Java_org_cocos2dx_lib_Cocos2dxRenderer_nativeInit(JNIEnv*  env, jobject thiz, jint w, jint h)
{
    if (!CCDirector::sharedDirector()->getOpenGLView())
    {
        CCEGLView *view = CCEGLView::sharedOpenGLView();
        view->setFrameSize(w, h);

        AppDelegate *pAppDelegate = new AppDelegate();
        CCApplication::sharedApplication()->run();
    }
    else
    {
        ccGLInvalidateStateCache();
        CCShaderCache::sharedShaderCache()->reloadDefaultShaders();
        ccDrawInit();
        CCTextureCache::reloadAllTextures();
        CCNotificationCenter::sharedNotificationCenter()->postNotification(EVENT_COME_TO_FOREGROUND, NULL);
        CCDirector::sharedDirector()->setGLDefaultValues();
    }
}

這似乎讓我們看到了游戲邏輯的入口了:

復制代碼 代碼如下:

    CCEGLView *view = CCEGLView::sharedOpenGLView();
    view->setFrameSize(w, h);

    AppDelegate *pAppDelegate = new AppDelegate();
    CCApplication::sharedApplication()->run();


繼續追蹤CCApplication::run方法:
復制代碼 代碼如下:

int CCApplication::run()
{
    // Initialize instance and cocos2d.
    if (! applicationDidFinishLaunching())
    {
        return 0;
    }

    return -1;
}

applicationDidFinishLaunching,沒錯這就是游戲邏輯的入口了。我們得回到Samples代碼目錄中去找到對應方法 的實現。

復制代碼 代碼如下:

//cocos2d-x-2.2.2/samples/Cpp/HelloCpp/Classes/AppDelegate.cpp

bool AppDelegate::applicationDidFinishLaunching() {
    // initialize director
    CCDirector* pDirector = CCDirector::sharedDirector();
    CCEGLView* pEGLView = CCEGLView::sharedOpenGLView();

    pDirector->setOpenGLView(pEGLView);
    CCSize frameSize = pEGLView->getFrameSize();
    … …

    // turn on display FPS
    pDirector->setDisplayStats(true);

    // set FPS. the default value is 1.0/60 if you don't call this
    pDirector->setAnimationInterval(1.0 / 60);

    // create a scene. it's an autorelease object
    CCScene *pScene = HelloWorld::scene();

    // run
    pDirector->runWithScene(pScene);

    return true;
}

的確,在applicationDidFinishLaunching中我們做了很多引擎參 數的設置。接下來大管家CCDirector實例登場,并運行了HelloWorld Scene的實例。但這依舊是初始化的一部分,雖然方法名讓人聽起來像是某種持續連貫行為:

復制代碼 代碼如下:

//cocos2d-x-2.2.2/cocos2dx/CCDirector.cpp

void CCDirector::runWithScene(CCScene *pScene)
{
    … …
    pushScene(pScene);
    startAnimation();
}

void CCDisplayLinkDirector::startAnimation(void)
{
    if (CCTime::gettimeofdayCocos2d(m_pLastUpdate, NULL) != 0)
    {
        CCLOG("cocos2d: DisplayLinkDirector: Error on gettimeofday");
    }

    m_bInvalid = false;
}


兩個方法均只是初始化了某些數據成員變量,并未真正將引擎驅動起來。


七、驅動引擎

之所以游戲畫面是運動的,那是因為屏幕以較高的幀數刷新的緣故,這樣人眼就會看到連續的動作,就和電影的放映原理是一樣的。在Cocos2d-x 引擎中這些驅動屏幕刷新的代碼在哪里呢?

我們回顧一下之前談到的GLThread線程,我們說過畫面渲染的工作都是由它來完成的。GLThread的核心是guardedRun函數,該 函數以“死循環”的方式調用Cocos2dxRender.onDrawFrame方法對畫面進行持續渲染。

我們來看看引擎實現的Cocos2dxRender.onDrawFrame方法:

復制代碼 代碼如下:

public void onDrawFrame(final GL10 gl) {
        /*
         * FPS controlling algorithm is not accurate, and it will slow down FPS
         * on some devices. So comment FPS controlling code.
         */

        /*
        final long nowInNanoSeconds = System.nanoTime();
        final long interval = nowInNanoSeconds 亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

久久久国产视频| 国产精品永久免费| 国内精品模特av私拍在线观看| www.国产一区| 性欧美xxxx交| 成人黄色在线免费| 亚洲欧美日韩国产成人| 69久久夜色精品国产69| 国语对白做受69| 欧美性在线视频| 日本精品久久久久影院| 国产精品av电影| 亚洲老司机av| 久久久国产精品视频| 欧美xxxx做受欧美.88| 91精品国产综合久久久久久久久| 中文字幕国产精品久久| 97在线免费观看视频| 午夜精品久久久久久久99热| 日韩有码在线电影| 国产精品男人的天堂| 97成人精品区在线播放| 亚洲专区国产精品| 欧美成人午夜免费视在线看片| 亚洲欧美中文日韩在线v日本| 国产成人久久久精品一区| 国产一区二区日韩| 91成人天堂久久成人| 亚洲欧美日韩在线一区| 国产999精品久久久影片官网| 国产成人一区二| 日本不卡高字幕在线2019| 亚洲成av人片在线观看香蕉| 亚洲欧美在线免费观看| 国产一区二区精品丝袜| 国产精品久久久久久久久久小说| 亚洲精品日韩欧美| 欧美日韩成人免费| 亚洲影视九九影院在线观看| 91精品久久久久久久久青青| 4k岛国日韩精品**专区| 韩曰欧美视频免费观看| 亚洲人成网在线播放| 亚洲福利视频网站| 91国产一区在线| 国产精品美女主播在线观看纯欲| 欧美视频二区36p| 国产精品自产拍在线观看| 国产精品∨欧美精品v日韩精品| 欧美色xxxx| 欧美裸体男粗大视频在线观看| 欧美性极品少妇精品网站| 日韩av电影在线免费播放| 久久成人精品电影| 97精品国产97久久久久久春色| 国产欧美一区二区三区视频| 成人激情视频在线播放| 精品久久久91| 97在线精品国自产拍中文| 日韩在线视频免费观看| 日韩欧美精品免费在线| 5566成人精品视频免费| 亚洲精品456在线播放狼人| 日韩欧美成人网| 亚洲黄色成人网| 久久国产精品99国产精| 亚洲精品自拍偷拍| 欧美日韩国产色| 久久99国产精品自在自在app| 菠萝蜜影院一区二区免费| www.国产一区| 欧美夫妻性生活视频| 成人精品久久久| 欧美性猛交xxxx免费看久久久| 久久久99免费视频| 欧美黑人巨大精品一区二区| 欧美乱人伦中文字幕在线| 精品无人区乱码1区2区3区在线| 尤物九九久久国产精品的分类| 黄色一区二区三区| 一区二区国产精品视频| 国产自摸综合网| 日本欧美精品在线| 国产日韩专区在线| 欧美性理论片在线观看片免费| 富二代精品短视频| 国产精品中文字幕在线观看| 亚洲精品综合久久中文字幕| 亚洲综合色激情五月| 国产亚洲欧洲在线| 九九九久久久久久| 日韩精品视频免费| 亚洲国产精品美女| 欧美黄网免费在线观看| 中文字幕一区日韩电影| 欧美一区三区三区高中清蜜桃| 一区二区三区美女xx视频| 亚洲欧洲在线视频| 91免费精品国偷自产在线| 日韩美女在线看| 亚洲精品xxx| 久久久国产精品x99av| 精品国内亚洲在观看18黄| 粉嫩老牛aⅴ一区二区三区| 日韩精品在线观看一区| 亚洲2020天天堂在线观看| 91精品国产高清久久久久久| 都市激情亚洲色图| 亚洲大胆人体视频| 亚洲一区二区国产| 国产精品视频永久免费播放| 亚洲精品永久免费精品| 日韩欧美成人精品| 欧美极品少妇全裸体| 亚洲一区二区在线| 正在播放亚洲1区| 一本色道久久综合狠狠躁篇的优点| 97久久超碰福利国产精品…| 亚洲精品国产精品乱码不99按摩| 亚洲午夜精品视频| 久久视频在线观看免费| 久久久人成影片一区二区三区观看| 91久久久久久久久久久久久| 尤物99国产成人精品视频| 亚洲精品一区av在线播放| 国自产精品手机在线观看视频| 国产一区二区日韩精品欧美精品| 2018日韩中文字幕| 国产日韩视频在线观看| 亚洲日本成人女熟在线观看| 国产高清视频一区三区| 欧美刺激性大交免费视频| 色妞久久福利网| 欧美一级高清免费| 热99在线视频| 青青久久av北条麻妃黑人| 欧美在线视频网站| 少妇高潮久久久久久潘金莲| 国产欧美韩国高清| 91精品视频在线看| 一级做a爰片久久毛片美女图片| 国产精品久久在线观看| 国产精品视频中文字幕91| 美日韩精品视频免费看| 日韩av电影在线网| 亚洲性69xxxbbb| 92国产精品久久久久首页| 亚洲有声小说3d| 欧美中文字幕在线| 亚洲精选中文字幕| 欧美电影免费观看电视剧大全| 亚洲欧美制服中文字幕| 日韩激情在线视频| 91精品中文在线| 国产免费一区视频观看免费| 97在线视频观看| 91国在线精品国内播放| 亚洲国产欧美一区二区丝袜黑人| 欧美激情手机在线视频| 国产精品视频久久| 亚洲石原莉奈一区二区在线观看| 亚洲一区av在线播放| 亚洲偷熟乱区亚洲香蕉av| 亚洲精品日韩欧美|