【連載】ジャンプ＆ランゲームを作ろう(6) いろんな床を生成しよう

# はじめに

こちらのQiitaは勝手連載「ジャンプ＆ランゲームを作ろう」になります。
初回の記事はこちらです。
[【連載】ジャンプ＆ランゲームを作ろう(1) プロジェクト作成](https://qiita.com/motoyasu-yamada/items/3fcc164cae23537b5f1a)
※お断り※ 毎日お昼休みに15分程度で執筆していおり細切れになりましてすみません

# 今日の内容

前回までに、床を自動生成し、床の上をボールが走りジャンプするところまで実装しました。

今回は様々な床を生成したいと思います。

ランダム生成型ジャンプ＆ランゲームを面白くするコツは

1. 床の固定パターンを組み合わせるだけでは面白くない
2. 床の生成ロジックパターンを数種類用意しつつ生成は乱数を使い揺らぎのある床を生成する

# 今回のソースコード
https://github.com/liberapp-inc/h5g-qiita-jump-and-run/tree/77ebfd206ded8ba2096f9467375f52cfa05813da

コミット内容(前回との差分)：
https://github.com/liberapp-inc/h5g-qiita-jump-and-run/commit/77ebfd206ded8ba2096f9467375f52cfa05813da

# 解説

## 8種類の地形

今回生成するプラットフォームは、平らな地面、上りの傾斜、下りの傾斜、上り階段、下り階段、崖、細かい穴の連続、大きな穴の、８パターンです。

```ts:Main.ts
enum PlatformGenerationMode {
    Flat,
    SlopeAscent,
    SlopeDescent,
    LevelsAscent,
    LevelsDescnet,
    Cliff,
    Pits,
    LargePit,
}
```

今回の記事では、平らな地面、上りの傾斜、下りの傾斜の３パターンのみ対応します。

`drawPlatformGenerationMode`は次にどの地形を生成するかを抽選するメソッドです。

今回は、3パターンが順にでるように手を抜いています。

```ts:Main.ts
    private drawPlatformGenerationMode() : PlatformGenerationMode{
        const patterns = [PlatformGenerationMode.Flat,PlatformGenerationMode.SlopeDescent,PlatformGenerationMode.SlopeAscent];
        return patterns[this.generationIndex % 3];
    }
```

地形ブロックの色を抽選するメソッドです。現在は、赤と白が交互に生成されるようになっています。

```ts:Main.ts
    private nextColor() : number {
        const c = this.colors[this.generationIndex % 2];
        this.generationIndex++;;
        return c;
    }
```

## 便利関数

`Math.random()`ですと 0～1までの乱数発生になります。

AからBまでの乱数の生成をしたいケースが頻発しますのでヘルパー関数を定義します。


```ts:Main.ts
function random(min:number,max:number) {
    return min + Math.random() * (max -min);
}
```

## 地形の生成

```ts:Main.ts
    private generateNewBlocks() {
        const generationBorder = this.cameraX + this.width;
        while(this.lastDrawnX  < generationBorder) {
            switch(this.drawPlatformGenerationMode()) {
                case PlatformGenerationMode.Flat:
                {
                    const len = random(3,10);
                    let x = 0;
                    for (let n = 0; n < len; n++) {
                        const p = new egret.Shape();
                        p.x = this.lastDrawnX;
                        p.y = this.lastDrawnY + random(-5,5);
                        p.graphics.beginFill(this.nextColor());
                        p.graphics.drawRect(0, 0, 32,32);
                        p.graphics.endFill();
                        this.world.addChild(p);
                        this.platforms.push(p);
                        this.lastDrawnX += p.width;
                        this.lastDrawnY = p.y;
                    }
                }
                break;
                case PlatformGenerationMode.SlopeDescent:
                {
                    const len = random(10,30);
                    const descent = random(7,10);
                    let x = 0;
                    for (let n = 0; n < len; n++) {
                        const p = new egret.Shape();
                        p.x = this.lastDrawnX;
                        p.y = this.lastDrawnY + descent + random(-5,5);
                        p.graphics.beginFill(this.nextColor());
                        p.graphics.drawRect(0, 0, 32,32);
                        p.graphics.endFill();
                        this.world.addChild(p);
                        this.platforms.push(p);
                        this.lastDrawnX += p.width;
                        this.lastDrawnY = p.y;
                    }
                }                
                case PlatformGenerationMode.SlopeAscent:
                {
                    const len = random(10,30);
                    const ascent = random(-10,-7);
                    let x = 0;
                    for (let n = 0; n < len; n++) {
                        const p = new egret.Shape();
                        p.x = this.lastDrawnX;
                        p.y = this.lastDrawnY + ascent + random(-5,5);
                        p.graphics.beginFill(this.nextColor());
                        p.graphics.drawRect(0, 0, 32,32);
                        p.graphics.endFill();
                        this.world.addChild(p);
                        this.platforms.push(p);
                        this.lastDrawnX += p.width;
                        this.lastDrawnY = p.y;
                    }
                }
                break;
                case PlatformGenerationMode.LevelsAscent:
                case PlatformGenerationMode.LevelsDescnet:
                case PlatformGenerationMode.Cliff:
                case PlatformGenerationMode.Pits:
                case PlatformGenerationMode.LargePit:
                break;
            }
        }
    }
```