利用JavaScript生成一張隨機的城市地圖

jopen 8年前發布 | 17K 次閱讀 向量 JavaScript開發 JavaScript

zz85在 這里 用簡單的代碼就生成了一張隨機的城市地圖。生成地圖與畫一棵隨機的樹十分相似,都是先給出初始的元素,每個元素在滿足條件時會生成新的子代,最后由所有的元素共同組成了我們想要的地圖或樹。

程序中創建的幾個對象

地圖中的每一條道路對應程序中的一個Boid對象,Boid對象中用兩個向量分別表示道路的起點和終點坐標。程序中的向量是使用 Three.js 這個庫中的 Vector2 對象來表示的。

// 使用three.js中的向量來表示
this.start = new THREE.Vector2(x, y);
this.end = new THREE.Vector2(x, y);

Boid對象還有這些屬性:

  • x,y :道路上距離起點最遠的坐標

  • angle :道路的角度,會在其父代角度基礎上偏轉一個隨機的角度

  • distance :這條道路的長度

  • dead :對象是否已經死亡

Boid還有一個 update 方法,它有如下的幾個功能:

  • 更新 x,y 坐標

    this.distance += 2;

    x = this.start.x + this.distance * this.dx;

    y = this.start.y + this.distance * this.dy;

    this.end.set(x, y);

  • 檢測相交情況,根據更新后的坐標作圖。

在程序中需要創建兩個數組用于保存 Boid 對象, boids 中存放當前存活的元素, all_boids 存放所有(包括存活和死亡)的元素。產生一個新元素時,會被同時放入兩個數組,當元素死亡后,將其從 boids 中移除。

對于一條道路A,它會一直向前延伸,直到與另一條道路相交,這時將A的狀態設置為dead。為了檢測相交,需要對 all_boids 數組中的元素進行遍歷。如果與其中的元素B出現了交點,可能是以下幾種情況:

  • A是B的子代

  • B是A的子代

  • B的終點在A上

  • A在延伸過程中遇上了B

這最后一種情況才是我們所需要的,將交點坐標賦給A的終點,將A從boids數組中刪去。以上檢查交點的過程發生在update()函數中。

開始構建程序

在程序開始時,首先創建四個元素來表示畫面的邊框。

var b1 = new Boid();
var b2 = new Boid();
var b3 = new Boid();
var b4 = new Boid();

b1.dead = b2.dead = b3.dead = b4.dead = true;

b1.start.set(0, 0);
b2.start.set(width, 0);
b3.start.set(width, height);
b4.start.set(0, height);

b1.end = b2.start;
b2.end = b3.start;
b3.end = b4.start;
b4.end = b1.start;

all_boids.push(b1);
all_boids.push(b2);
all_boids.push(b3);
all_boids.push(b4);

然后創建第一個 boid ,它的坐標在畫面的中間

var b = new Boid(width/2, height/2, Math.random() * 2 * Math.PI);
boids.push(b);
all_boids.push(b);

調用 setInterval 函數進入循環,首先檢查 boids.length ,如果當前沒有存活的 boid ,則退出循環,程序完成。否則遍歷所有存活的 Boid ,更新其狀態。在滿足如下的幾個條件時生成子代。

  1. 沒有死亡

  2. 只有0.1的概率產生子代

  3. 當前所有存活元素的數量小于50

    for (i = 0; i < boids.length; i++) {

       var b = boids[i];
       b.update();
    
       // 產生子代的幾個條件:
       // 1. 沒有死亡
       // 2. 只有0.1的概率產生子代
       // 3. 當前所有存活元素的數量小于50
       if (!b.dead && Math.random()>0.9 && boids.length < 50) {
           var child = new Boid(b.end.x, b.end.y,
               b.angle + Math.PI * (Math.random() > 0.5 ? 0.5 : -0.5));
           child.parent = b;
          // child.fillStyle = getRndColor();
           boids.push(child);
           all_boids.push(child);
       }

    }

最終當存活的Boid數量為零時,程序運行完畢,就得到了一張隨機的城市道路地圖。當然,現在的地圖還只是 2D 的版本,想生成 3D 的城市,可以查看下面的參考資料中zz85的博客。

代碼及演示

我在GitHub上的代碼地址

在線的 demo

參考資料

本文原發表在 我的博客 上。

來自: http://segmentfault.com/a/1190000004284885

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!