three.js 製作邏輯轉體遊戲(上)

郭先生的部落格發表於2020-08-19

今天郭先生又出來製作遊戲了,最近有小夥伴要做一個邏輯轉體小遊戲,我怎麼能不先來試試呢。玩法可以看上面的連線,下面附幾張圖。線案例請點選部落格原文

 

遊戲規則不懂得可以看自行百度哈,其實玩起來還挺有難度的。關於這個問題,對於新手來說,主要需要克服兩個困難。一是這個模型的旋轉軸不是固定的,每一次的旋轉都是以不同的一個邊為軸進行的。二是需要根據關卡資料渲染終點位置和陷阱(這裡使用shader)。那麼我們今天就來完成第一個難點,如何讓幾何體動態的繞非定軸轉動。我們還是一步一步來。

1. 關卡資料以及其他變數的設定

對於一個闖關型別的遊戲,設定好關卡資料和結構是十分必要的,能夠讓程式碼簡介高效。

var boxes = [], group = new THREE.Group(), box3, uniforms
var square = [
    {
        start: [[-1, -1], [-1, -2]],
        end: [[-1, -4], [-1, -5]],
        trap: [[-1, -7], [-6, -2]],
        color: 0xDC210E
    },
    {
        start: [[-2, -1], [-3, -1], [-2, -2], [-3, -2]],
        end: [[-5, -6], [-6, -6], [-5, -7], [-6, -7]],
        trap: [[-1, -7], [-6, -2]],
        color: 0x097A53
    },
    {
        start: [[-1, -1], [-1, -2], [-1, -3], [-2, -1], [-2, -3]],
        end: [[-1, -6], [-1, -8], [-2, -6], [-2, -7], [-2, -8]],
        trap: [[-1, -7], [-6, -2]],
        color: 0x1B2991
    }
];

因為不同關卡使用的道具是不一樣的,boxes就是盛放每一關小方塊的盒子,而繞非定軸轉動的主角就是這個group,因為Object3D轉動都是繞穿過中心的軸轉動的,所以我們需要將小方塊放到一個組中,並且讓小方塊相對組中心產生偏移,這樣旋轉組,我們看小方格的轉動就是繞非定軸的轉動了。box3在3D空間中表示一個盒子或立方體。其主要用於表示物體在世界座標中的邊界框,我前面也講過,不會的也可以往前翻翻,它所能完成的功能,我們通過計算也都可以完成,但是它類似於一個方法類,可以極大的簡化我們的計算,稍後我會用到一些。uniforms是向著色器傳入一些變數值的,這篇暫時用不到。square儲存著每一關的資料,start是初始位置,end是結束位置,trap是陷阱位置,color是小方塊的顏色。位置座標我們稍後再研究。

2. 佈局和初始化小方塊

首先看一下我是我們們佈局的(這個因人而異)。

看這個圖大家就懂了,我是將邏輯轉體的面放在了XOZ面上,並將平面放在了x和z的負半軸,因此他們的座標都是負值,每一個格子的邊長都是10,所以關卡資料start: [[-1, -1], [-1, -2]]代表01格和08格,這樣我們就可以將座標對映到格子上。有了這個對映我們很容易根據資料初始化小方格。

initBox() {
    let geom = new THREE.BoxGeometry(10, 10, 10);
    let mate = new THREE.MeshBasicMaterial({color: square[this.game].color, transparent: true, opacity: .8});
    let mesh = new THREE.Mesh(geom, mate);
    boxes = [];
    square[this.game].start.forEach((d,i) => {
        let meshCopy = mesh.clone();
        meshCopy.position.set(d[0] * 10+ 10 / 2, 10 / 2, d[1] * 10 + 10 / 2);
        meshCopy.name = 'box-' + i;
        boxes.push(meshCopy);
        scene.add(meshCopy)
    })
    this.computedBox3();
},

這段程式碼比較簡單,小做出一個小方塊的Mesh,然後根據對映關係,將方塊的拷貝放到該放的位置,並將小方塊都放在boxes中。在每一關初始化方塊後,我們都要計算一下這些小方塊集合的box3,因為有了小放塊集合很容易得到box3,而有了box3我們又很容易知道小方塊集合的邊界和中心。

3. 實現非定軸旋轉

現在我們有了所有小方塊的集合boxes和box3,現在我們就根據上下左右的點選事件實現非定軸轉動,先看下圖。

就拿這一關來說,假如我們讓它向右轉,圖一的圖形會以右下角那條邊旋轉到圖二,下面來看看向右轉的程式碼。

var offset = new THREE.Vector3(box3.max.x, 0, 0);
group.position.copy(offset);
boxes.forEach(d => {
    d.position.sub(offset);
    group.add(d);
})
scene.add(group);

這裡是最難理解的地方,因為我們的小方格的之前的matrix就已經是matrixWorld了(因為在scene.children中)將他們新增到一個組,再旋轉組肯定得不到我們想要的結構(因為新加的組預設還是在原點),所以呢這裡我們來了一個乾坤大挪移,將小方格向右移,將組向左移動相同的向量。

這樣子小方塊就在這個位置了(將入組之後,就相當於在組的這個位置),這樣子旋轉後,就成了我們想要的樣子,而這個向量就是這個offset,box3.max.x是小方塊集boxes的x方向的上限。再旋轉完之後呢,我們又要把組去掉(這個組就像一個殼一樣,轉完了就脫掉哈哈)。

awayFromGroup() {
    boxes.forEach(d => {
        var trans = new THREE.Vector3();
        d.matrixWorld.decompose(trans, new THREE.Quaternion(), new THREE.Vector3());
        d.position.copy(trans);
        d.updateMatrixWorld();
        scene.add(d)
    })
    scene.remove(group);
    this.computedWin();
    this.computedBox3();
},

這裡我們找到小方塊的世界矩陣,找到位置向量trans就可以,然後將小方格重新賦予位置,這裡將小方格直接新增到場景中。這樣子就完成了乾坤大挪移,其他的方向也都類似哦,別忘了在計算box3哦,因為下一步還要使用哦,

這一篇就先講繞非定軸轉動啦,對於新手來說,這確實需要理解一下,那就先講到這了,下一篇繼續。

轉載請註明地址:郭先生的部落格

相關文章