iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 18
1

引言

昨天我們稍微將structlinklist研究了一下後,
今天應該就有足夠的技術來實現放置方塊功能啦~

我們會對已經完成的第一版3D引擎做一些改造,
改造方向如下:

  1. 建立Cube型態的struct
  2. 建立由世界中所有Cube組成的linklist
  3. 將render_screen中原先預設直接寫死render_cube的位置,改成讀取linklist裡所有Cube資料並繪製出來
  4. 新建立按鈕「m」:按下後在離攝影機最近的整數座標點上放置一個方塊,此方塊會被新增到linklist中,被下一次的render_screen繪製出來

建立Cube型態的struct

我們在"Renderer.h"的變數定義上方加上新的Cube結構定義

/* File: Renderer.h */

#ifndef __RENDERER_H__
#define __RENDERER_H__

#define _CLEAN_MODE_ 0
#define _RENDER_MODE_ 1

// ------------新增部分-------------------
typedef struct cube  // 定義方塊
{
    struct cube *next;  // 指向下一塊方塊
    char style;  // 以下屬性是render_cube函數所需參數,
    int cx;      // 同時也是繪製方塊所需的資料。
    int cy;      // 我們可以在玩家按下"m"的時候將方塊資訊加入到linklist中,
    int cz;      // 此方塊就正式「加入」這個世界,
    int left;    // 因為往後的每次render_screen都會將linklist中所有方塊繪製出來。
    int right;
    int top;
    int bottom;
    int f;
    int r;
}Cube;

Cube allCubesHead;  // linklist的頭,標的物
Cube *allCubes;     // Cube指標,用來依序指向每一塊方塊
Cube newCube;       // 遊戲開始時預設在世界中的方塊,也就是類似以前的「大平台」
// --------------------------------------

float camera_x_pos, camera_y_pos, camera_z_pos;
float camera_speed;
float fov;
...
..
.

世界預設存在的方塊設定

我們會先把上述的newCube指定好所有參數,當作遊戲開始時預設會存在的方塊,
這部分會在init_renderer也就是renderer初始化的時候跟變數們一起初始化。

/* File: Renderer.c */

void init_renderer()
{
    camera_x_pos = 0.0;
    camera_y_pos = 0.0;
    camera_z_pos = -150;
    camera_speed = 5.0;
    fov = 120;
    x1 = 0.0;
    y1 = 0.0;
    z1 = 0.0;
    x2 = 0.0;
    y2 = 0.0;
    z2 = 0.0;
    rx = 1;
    ry = 1;
    rot_x = 0.0;
    rot_y = 0.0;
    sin_x = 0.0;
    cos_x = 0.0;
    sin_y = 0.0;
    cos_y = 0.0;
    
// ------------新增部分-------------------
    allCubes = &allCubesHead;  // 指標先指到開頭
    allCubes->next = &newCube;  // 將newCube連上開頭
    allCubes = allCubes->next;  // 指標移動到newCube上
    allCubes->next = NULL;  // newCube先將下一塊的位址設為NULL
    allCubes->cx = 0;       // 以下為設定各項屬性
    allCubes->cy = 5;
    allCubes->cz = -150;
    allCubes->left = 50;
    allCubes->right =50;
    allCubes->top = 2;
    allCubes->bottom = 2;
    allCubes->f = 50;
    allCubes->r = 50;
    allCubes = &allCubesHead;  // 指標回到開頭
// --------------------------------------
}

改變render_screen的方式

原先是寫死的繪製哪些方塊,現在需要動態繪製
,因此我們採用每次都讀取linklist來確認目前有哪些方塊

void render_screen(int mode)
{
    char render_style = '#';

    if(mode == _CLEAN_MODE_)
    {
        render_style = ' ';
    }
    else if(mode == _RENDER_MODE_)
    {
        render_style = '#';
    }
    else  /* Default */
    {
        render_style = '#';
    }

    calc_tri();  /* Here Must Calculate Again */

// ------------新增部分-------------------
    while(allCubes->next != NULL)  // 直到linklist到尾端前都
    {
        render_cube(render_style, allCubes->next->cx, allCubes->next->cy, allCubes->next->cz,
                    allCubes->next->left, allCubes->next->right, allCubes->next->top,
                    allCubes->next->bottom, allCubes->next->f, allCubes->next->r);
        allCubes = allCubes->next;  // 繪製每一塊方塊,指標指到下一個
    }
    allCubes = &allCubesHead;       // 都畫完後指標回到開頭
// --------------------------------------
}

建立m按鍵功能

我們設計成,將離目前位置最近的座標及其他資訊寫入到linklist的最尾端,讓下次render_screen能夠將其畫出來。

/* File: main.c */
        .
        ..
        ...
        // 寫在其他按鍵判斷下
        if(GetAsyncKeyState(77) != 0)  /*M*/  // put a cube
        {
            render_screen(_CLEAN_MODE_);
            while(allCubes->next != NULL)  // 將指標移到最後一塊
            {
                allCubes = allCubes->next;
            }
            
            allCubes->next = (Cube *)malloc(sizeof(Cube));  // 用malloc配置一塊方塊接到下一塊
            allCubes = allCubes->next;  // 指標移動到新方塊
            allCubes->cx = camera_x_pos;  // 以下設置所有屬性
            allCubes->cy = camera_y_pos;
            allCubes->cz = camera_z_pos;
            allCubes->style = '#';
            allCubes->left = 2;
            allCubes->right = 2;
            allCubes->top = 2;
            allCubes->bottom = 2;
            allCubes->f = 2;
            allCubes->r = 2;
            allCubes->next = NULL;
            allCubes = &allCubesHead;  // 指標移動回頭
            render_screen(_RENDER_MODE_);
            isFrameUpdated = True;
        }

執行

作者測試在程式中創立了三個方塊:

https://ithelp.ithome.com.tw/upload/images/20191002/20111429o8WBaGoJJv.png

轉個角度看:
https://ithelp.ithome.com.tw/upload/images/20191002/20111429GMtnGOEyBy.png

https://ithelp.ithome.com.tw/upload/images/20191002/20111429WhxrfXI9rc.png
這是接近初始大平台上方的,可以看出「遠近處理」幾乎不存在,因為這需要牽涉光影、深淺等細節,
這次的主題就不贅述啦~


尾聲

這次主題的3D部分就告一段落啦,往後幾天會帶大家來體驗2D遊戲製作,
會製作類似魔塔的遊戲,就敬請期待囉~


上一篇
[11屆鐵人賽Day17] 3D引擎製作(七)—放置方塊(上)(struct, linklist介紹)
下一篇
[11屆鐵人賽Day19] 進入2D世界—聲音播放:PlaySound
系列文
若沒有遊戲引擎、合作夥伴...做得出遊戲嗎? 不試試看不知道吧? [使用C語言]30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言