【Unity】スクリプトで円形にオブジェクトを配置する

投稿者: | 2020-04-20


スクリプトで円形にオブジェクトを配置してみます。上の画像の横軸をZ軸、縦軸をX軸とし、中心(0, 0)からZ軸に沿って半径の分だけ離れた位置に1つ目のオブジェクトを置きました。
次に、1つ目と2つ目のなす角θを使って、2つ目のオブジェクトの座標を求めます。

下の三角形の斜めの辺と底の辺の長さをa、bとすると、コサインθ = b / a なので、b = a * コサインθ です。

なので、最初の画像の2つ目のオブジェクトのz座標は、半径 * コサインθ です。同様に、x座標は 半径 * サインθで求められます。
θは、360度 / 配置するオブジェクトの数 で決まります。つまり、半径とオブジェクトの数がわかれば上の計算ができます。
3つ目のオブジェクトは角度θを2倍、4つ目は3倍します。

中心の座標を表す空のオブジェクトにスクリプトをつけます。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CircleEmitScript : MonoBehaviour
{
    [SerializeField] GameObject ball;
    [SerializeField] float radius = 2f;
    [SerializeField] int count = 6;
    [SerializeField] float power = 10f;
    [SerializeField] float Lifetime = 3f;
    List<GameObject> balls;

    // Start is called before the first frame update
    void Start()
    {
        if (radius == 0) radius = 0.1f;

        balls = new List<GameObject>();

        Vector3 pos; // 配置するオブジェクトの位置
        Vector3 defPos; // 中心の位置
        Quaternion rot = transform.rotation;
        float radian = Mathf.PI * 2 / count; // オブジェクトの数から角度を決める

        pos = transform.position;
        defPos = transform.position;
        pos.z += radius; // Z軸に沿って半径の分だけ移動

        balls.Add(Instantiate(ball, pos, rot)); // 1つ目のボールを生成
        balls[0].GetComponent<Rigidbody>().AddForce((pos - defPos) * power, ForceMode.Impulse); // 中心からの方向に力を加える

        // 2つ目以降
        for (int n = 0; n < count - 1; n++)
        {
            // 置く位置を計算
            pos.z = Mathf.Cos(radian * (n + 1)) * radius + defPos.z;
            pos.x = Mathf.Sin(radian * (n + 1)) * radius + defPos.x;
        
            balls.Add(Instantiate(ball, pos, rot)); // ボールを生成
            balls[n + 1].GetComponent<Rigidbody>().AddForce((pos - defPos) * power, ForceMode.Impulse); // 力を加える
        }

        /*
        for (int n = 0; n < count - 1; n++)
        {
            pos.z += Mathf.Cos(radian * (n + 1)) * radius;
            pos.x += Mathf.Sin(radian * (n + 1)) * radius;

            Instantiate(ball, pos, rot); // 2つ目以降

        }*/

        Invoke("DestroyBall",Lifetime);

    }

    void DestroyBall()
    {
        // ボールを全て削除
        balls.ForEach(b => { Destroy(b); });

        // 中心を削除
        Destroy(gameObject);
    }

}

2つ目以降はループ処理で配置します。配置した後、花火のように外側にオブジェクトを飛ばしています。
求めた座標に中心の座標を加えて、中心を動かしても円形が崩れないようにしています。
コメントアウトした方でも円形に配置できますが、中心が円の真ん中になりません。

時間が立つと、配置したオブジェクトと中心がシーンから削除されるようにしています。

このスクリプトが付いた中心のオブジェクトとボールをプレハブ化します。

そして、この中心のオブジェクトを生成するスクリプトをつけた空のゲームオブジェクトをシーンに配置します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class GenerateCircleScript : MonoBehaviour
{
    //[SerializeField] GameObject ball;
    [SerializeField] GameObject center;
    public Plane plane;

    // Start is called before the first frame update
    void Start()
    {
        // text.text = "";
        plane = new Plane(Vector3.up, Vector3.zero);
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {

            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            float dist;

            if (plane.Raycast(ray, out dist))
            {
                Instantiate(center, ray.GetPoint(dist), transform.rotation);
            }
        }

    }
}

Plane.Raycastを使って、マウスクリックした方向に飛ばしたレイと、ワールドの(0, 0, 0)の位置に真上を向けて置いた見えない平面との交点に、ボールを円形に配置する中心オブジェクトを配置します。

これで、クリックした場所にオブジェクトが円形に生成されて波紋の様に広がります。

半径や個数、飛ばす力などはインスペクタから設定できます。

1個

2個

3個

6個

9個

360個

コメントを残す

メールアドレスが公開されることはありません。