見出し画像

【Unity】沙羅曼蛇のテトランのアルゴリズムを再現してみる

沙羅曼蛇やグラディウスシリーズに出てくるテトランっぽい敵が作ってみたいと思い実装してみました。

アルゴリズムを検索してみてもあまり出てこなかったので忘備録として書いておきます。
考え方としては
1本目、腕の中心から決めた角度の腕の長さの円を描ける座標計算をします。その計算した座標を2本目の中心座標とします。

2本目、1本目で計算した中心座標から決めた角度の腕の長さの円を描ける座標計算をします。その計算した座標を3本目の中心座標とします。

3本目、2本目で計算した中心座標から決めた角度の腕の長さの円を描ける座標計算をします。その計算した座標を4本目の中心座標とします。
以下腕の長さだけ繰り返し。
要は普通に多関節の腕を作る感じです。
このまま回転させてもファンタジーゾーンのウインクロンみたいな感じで腕は真っすぐのままなのですが、ここで各腕に回転させる角度を一定の間隔で少しづつずらしてプラスするとテトランのようにウネウネする感じで回転してくれます。

ソースだとこんな感じ。
中心の腕が親、続く腕が子というイメージです。

        Vector3 pos1 = transform.position;
//1本目の計算
        pos[0] = transform.GetChild(0).position;
        pos[0].x = pos1.x;//腕の中心座標
        pos[0].y = pos1.y;//腕の中心座標
        pos[0].z = -0.1f;
        rad[0] += 0.05f;
        ds[0] = 0.4f;
        ux[0] = Mathf.Cos(rad[0]) * ds[0] + pos[0].x;//次の腕の中心座標
        uy[0] = Mathf.Sin(rad[0]) * ds[0] + pos[0].y;//次の腕の中心座標
        transform.GetChild(0).rotation = Quaternion.Euler(0, 0, (rad[0] * Mathf.Rad2Deg));//回転表示
        transform.GetChild(0).position = pos[0];
//2本目の計算
        pos[1] = transform.GetChild(1).position;
        pos[1].x = ux[0];//腕の中心座標
        pos[1].y = uy[0];//腕の中心座標
        pos[1].z = -0.2f;
        rad[1] += 0.05f;
        ds[1] = 0.4f;
        ux[1] = Mathf.Cos(rad[1]) * ds[1] + pos[1].x;
        uy[1] = Mathf.Sin(rad[1]) * ds[1] + pos[1].y;
        transform.GetChild(1).rotation = Quaternion.Euler(0, 0, (rad[1] * Mathf.Rad2Deg));//回転表示
        transform.GetChild(1).position = pos[1];
//3本目の計算
        pos[2] = transform.GetChild(2).position;
        pos[2].x = ux[1];//腕の中心座標
        pos[2].y = uy[1];//腕の中心座標
        pos[2].z = -0.3f;
        rad[2] += 0.05f;
        ds[2] = 0.4f;
        ux[2] = Mathf.Cos(rad[2]) * ds[2] + pos[2].x;//次の腕の中心座標
        uy[2] = Mathf.Sin(rad[2]) * ds[2] + pos[2].y;//次の腕の中心座標
        transform.GetChild(2).rotation = Quaternion.Euler(0, 0, (rad[2] * Mathf.Rad2Deg));//回転表示
        transform.GetChild(2).position = pos[2];
以下腕の数だけ繰り返し・・・

キーボードQボタンを押すと腕がウネウネする。
        if (Input.GetKey(KeyCode.Q))
        {
            rad[0] += 0.06f;
            rad[1] += 0.04f;
            rad[2] += 0.02f;
            rad[3] += 0.0f;
        }

初期設定時にradの値を0~6.28の間で設定すれば好きな向きに腕を伸ばす事が出来ます。

上記を纏めるとこんな感じ。

        float rad_plus = 0.05f
        Vector3 pos1 = transform.position;
        for (int i = 0; i < emax; i++)
        {
            pos[i] = transform.GetChild(0).position;
            if (i == 0)//腕の中心
            {
                pos[i].x = pos1.x;//腕の中心座標
                pos[i].y = pos1.y;//腕の中心座標
            }
            if (i != 0)//中心以外~先端まで
            {
                pos[i].x = ux[i - 1];
                pos[i].y = uy[i - 1];
            }
            pos[i].z = -i;
            
            rad[i] += rad_plus;
            ds[i] = 0.4f;
            ux[i] = Mathf.Cos(rad[i]) * ds[i] + pos[i].x;//次の腕のx座標
            uy[i] = Mathf.Sin(rad[i]) * ds[i] + pos[i].y;//次の腕のy座標
            transform.GetChild(i).rotation = Quaternion.Euler(0, 0, (rad[i] * Mathf.Rad2Deg));
            transform.GetChild(i).position = pos[i];
        }
        if (Input.GetKey(KeyCode.Q))
        {
            for (int i = 0; i < emax; i++)
            {
                float j;
                j = i;
                rad[i] += rad_plus - (j / 100);//腕を回転させる
            }
        }

腕の画像は下記画像のような中心から外側に向かうような画像にしておかないと上手く腕が繋がりません。

この記事が気に入ったらサポートをしてみませんか?