1. 程式人生 > 實用技巧 >二、Resources入門--正方形鍵位控制

二、Resources入門--正方形鍵位控制

效果圖如下所示:

image

整體的流程圖如下

image

主要需要實現以下兩部分:

  • 繪製正方形
  • 特殊鍵位移動函式

繪製正方形

在之前的三角形繪製中,我們已經瞭解了圖形繪製的一個基本流程,那麼正方形的繪製就是水到渠成的,只需要在三角形程式碼的基礎上做以下修改:

  • 定義頂點到原心距離,即 正方形邊長 = blockSize * 2
GLfloat blockSize = 0.1f;

  • 修改頂點陣列
//正方形四個點的座標
GLfloat vVerts[] = {
    -blockSize, -blockSize, 0.0f,
    blockSize, -blockSize, 0.0f,
    blockSize, blockSize, 0.0f,
    -blockSize, blockSize, 0.0f,
};

  • 修改setupRC函式中圖元的連線方式
//將 GL_TRIANGLES 修改為 GL_TRIANGLE_FAN ,4個頂點
    triangleBatch.Begin(GL_TRIANGLE_FAN, 4);

到此,正方形就繪製完成了,接下來我們需要完成正方形鍵位控制效果

鍵位控制效果

主要是指正方形根據選擇鍵盤的上下左右鍵移動。

該效果的實現有兩種方式

  • 座標更新方式
  • 矩陣方式

打個比方,有100件需要染同一種顏色的衣服,你可以選擇一件一件的染色,也可以選擇同時將100件放入染缸,一起染色,

  • 其中一件一件染色指代的就是座標更新方式,適用於頂點較少的圖形,
  • 同時放入染色指代的就是矩陣方式,當圖形頂點非常多的,再用座標更新就不合適了,需要使用矩陣來同時更新。

座標更新方式

頂點根據相對頂點逐個更新頂點座標,在SpecialKeys函式中完成鍵位移動時座標的更新,並手動呼叫渲染。

三個自定義函式的流程圖如下:

image

ChangeSize和RenderScene就不做解釋了,在繪製時,這部分已經完成了,主要說說SpecialKeys函式

  • 首先需要定義一個步長

  • 定義一個相對頂點的x和y值
    假設正方形如下圖所示,以D為相對頂點

    image
  • 根據鍵位方向,分別更新x 和 y

  • 邊緣碰撞處理
    如果沒有這個步驟,圖形移動到邊緣時,就會移動到螢幕不可見的區域,下圖可以說明4個方向對邊緣碰撞處理是如何計算的,這裡就不做詳細說明了

    image

具體的程式碼實現如下:

//key 列舉值,x、y是位置
void SpecialKeys(int key, int x, int y){
    //步長
    GLfloat stepSize = 0.025f;

    //相對點的座標
    GLfloat blockX = vVerts[0];
    GLfloat blockY = vVerts[10];

    printf("v[0] = %f\n",blockX);
    printf("v[10] = %f\n",blockY);

    //根據移動方向,更新相對座標
    if (key == GLUT_KEY_UP) {
        blockY += stepSize;
    }
    if (key == GLUT_KEY_DOWN) {
        blockY -= stepSize;
    }
    if (key == GLUT_KEY_LEFT) {
        blockX -= stepSize;
    }
    if (key == GLUT_KEY_RIGHT) {
        blockX += stepSize;
    }

    //觸碰到邊界(4個邊界)的處理

    //當正方形移動超過最左邊的時候
    if (blockX < -1.0f) {
        blockX = -1.0f;
    }
    //當正方形移動到最右邊時
    //1.0 - blockSize * 2 = 總邊長 - 正方形的邊長 = 最左邊點的位置
    if (blockX > (1.0f - blockSize * 2)) {
        blockX = 1.0f - blockSize * 2;
    }
    //當正方形移動到最下面時
    //-1.0 - blockSize * 2 = Y(負軸邊界) - 正方形邊長 = 最下面點的位置
    if (blockY < -1.0f + blockSize * 2) {
        blockY = -1.0f + blockSize * 2;
    }
    //當正方形移動到最上面時
    if (blockY > 1.0f) {
        blockY = 1.0f;
    }

    printf("blockX = %f\n",blockX);
    printf("blockY = %f\n",blockY);

    //重新計算正方形的位置
    //一個頂點有三個數 x、y、z
    vVerts[0] = blockX;
    vVerts[1] = blockY - blockSize * 2;
    printf("(%f,%f)\n",vVerts[0],vVerts[1]);

    vVerts[3] = blockX + blockSize * 2;
    vVerts[4] = blockY - blockSize * 2;
    printf("(%f,%f)\n",vVerts[3],vVerts[4]);

    vVerts[6] = blockX + blockSize * 2;
    vVerts[7] = blockY;
    printf("(%f,%f)\n",vVerts[6],vVerts[7]);

    vVerts[9] = blockX;
    vVerts[10] = blockY;
    printf("(%f,%f)\n",vVerts[9],vVerts[10]);

    //更新頂點資料
    triangleBatch.CopyVertexData3f(vVerts);

    //重新渲染提交 --> RenderScene
    glutPostRedisplay();

}

矩陣方式

主要是根據x軸、y軸移動的距離,生成一個平移矩陣,通過圖形*平移矩陣 = 移動後的圖形,得到最終效果

涉及兩個函式:RenderScene、SpecialKeys

矩陣方式中自定義函式的流程如下:

image

SpecialKeys 函式

  • 定義步長及兩個全域性變數(相對於x軸和y軸的平移距離)
//記錄移動圖形時,在x軸上平移的距離
GLfloat xPos = 0.0f;
//記錄移動圖形時,在y軸上平移的距離
GLfloat yPos = 0.0f;

GLfloat stepSize = 0.025f;

  • 根據移動方向,計算移動距離

  • 邊緣碰撞處理
    其移動距離計算的理解如圖所示
    ==> 可以將初始化的平移距離理解為正方形的中心,即原點,在圖形移動時,其中心點也發生了移動,所以我們要計算的邊緣的移動距離就是兩個中心店之間的平移距離

    image
  • 手動觸發重新渲染

具體實現如下:

//使用矩陣方式(一起搞定),不需要修改每個頂點,只需要記錄移動步長,碰撞檢測
void SpecialKeys(int key, int x, int y){

    GLfloat stepSize = 0.025f;

    if (key == GLUT_KEY_UP) {

        yPos += stepSize;
    }

    if (key == GLUT_KEY_DOWN) {
        yPos -= stepSize;
    }

    if (key == GLUT_KEY_LEFT) {
        xPos -= stepSize;
    }

    if (key == GLUT_KEY_RIGHT) {
        xPos += stepSize;
    }

    //碰撞檢測 xPos是平移距離,即移動量
    if (xPos < (-1.0f + blockSize)) {

        xPos = -1.0f + blockSize;
    }

    if (xPos > (1.0f - blockSize)) {
        xPos = 1.0f - blockSize;
    }

    if (yPos < (-1.0f + blockSize)) {
        yPos = -1.0f + blockSize;
    }

    if (yPos > (1.0f - blockSize)) {
        yPos = 1.0f - blockSize;
    }

    glutPostRedisplay();

}

RenderScene 函式
主要步驟如下:

  • 清理特定快取區
  • 根據平移距離計算平移矩陣
  • 將矩陣結果交給儲存著色器(平面著色器)中繪製
    在位置更新方式中,使用的是單元著色器,而矩陣方式中,涉及的矩陣是4*4的,單元著色器不夠用,所以使用平面著色器

具體的程式碼實現如下

//開始渲染
void RenderScene(void)

{
    //1.清除一個或者一組特定的快取區
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    //1.設定顏色RGBA
    GLfloat vRed[] = {1.0f, 0.5f, 0.0f, 1.0f};

    //定義矩陣
    M3DMatrix44f mTransformMatrix;

    //平移矩陣
    m3dTranslationMatrix44(mTransformMatrix, xPos, yPos, 0.0f);

    //當單元著色器不夠用時,使用平面著色器
    //引數1:儲存著色器型別
    //引數2:使用什麼矩陣變換
    //引數3:顏色
    shaderManager.UseStockShader(GLT_SHADER_FLAT, mTransformMatrix, vRed);

    //提交著色器
    triangleBatch.Draw();
    glutSwapBuffers();
}