创建具有基于大小的重力的游戏对象

本文关键字:游戏 对象 于大小 创建 | 更新日期: 2023-09-27 18:19:59

我在c#和unity中构建了一个基于分形的对象生成器,它构建了对象的分支,然后使用碰撞器和刚体相互反弹。现在,他们互相撞击,并不断地移动,距离越来越远。我想做的是给每个物体分配一定程度的引力,这样即使它们在碰撞中被排斥,它们也会把自己拉回来。除了工作之外,我什么都做了,除了重力方面。有没有人有这方面的经验,不介意给我一些指导?谢谢

using UnityEngine;
using UnityEngine.UI;
using System.Collections;
public class BuildFractal : MonoBehaviour 
{
    public Mesh[] meshes;
    public Material material;
    public Material[,] materials;
    private Rigidbody rigidbody;
    public int maxDepth;             // max children depth
    private int depth;
    public float childScale;         // set scale of child objects
    public float spawnProbability;   // determine whether a branch is created or not
    public float maxRotationSpeed;   // set maximium rotation speed
    private float rotationSpeed;
    public float maxTwist;
    public Text positionText;
    // Create arrays for direction and orientation data
    private static Vector3[] childDirections = {
        Vector3.up,
        Vector3.right,
        Vector3.left,
        Vector3.forward,
        Vector3.back,
        // Vector3.down
    };
    private static Quaternion[] childOrientations = {
        Quaternion.identity,
        Quaternion.Euler(0f, 0f, -90f),
        Quaternion.Euler(0f, 0f, 90f),
        Quaternion.Euler(90f, 0f, 0f),
        Quaternion.Euler(-90f, 0f, 0f),
        // Quaternion.Euler(180f, 0f, 0f)
    };
    private void Start () 
    {
        rotationSpeed = Random.Range(-maxRotationSpeed, maxRotationSpeed);
        transform.Rotate(Random.Range(-maxTwist, maxTwist), 0f, 0f);
        if (materials == null)
        {
            InitializeMaterials();
        }
        // Select from random range of meshes
        gameObject.AddComponent<MeshFilter>().mesh = meshes[Random.Range(0, meshes.Length)];
        // Select from random range of colors
        gameObject.AddComponent<MeshRenderer>().material = materials[depth, Random.Range(0, 2)];
        // Add a collider to each object
        gameObject.AddComponent<SphereCollider>().isTrigger = false;
        // Add Rigigbody to each object
        gameObject.AddComponent<Rigidbody>();
        gameObject.GetComponent<Rigidbody>().useGravity = false;
        gameObject.GetComponent<Rigidbody>().mass = 1000;
        // Create Fractal Children
        if (depth < maxDepth)
        {
            StartCoroutine(CreateChildren());
        }
    }
    private void Update ()
    {
        transform.Rotate(0f, rotationSpeed * Time.deltaTime, 0f);
    }
    private IEnumerator CreateChildren ()
    {
        for (int i = 0; i < childDirections.Length; i++)
        {
            if (Random.value < spawnProbability)
            {
                yield return new WaitForSeconds(Random.Range(0.1f, 1.5f));
                new GameObject("Fractal Child").AddComponent<BuildFractal>().Initialize(this, i);
            }
            /*if (i == childDirections.Length)
            {
                DestroyChildren();
            }*/
            // positionText.text = transform.position.ToString(this);
        }
    }
    private void Initialize (BuildFractal parent, int childIndex)
    {
        maxRotationSpeed = parent.maxRotationSpeed;
        // copy mesh and material references from parent object
        meshes = parent.meshes;
        materials = parent.materials;
        maxTwist = parent.maxTwist;
        // set depth and scale based on variables defined in parent
        maxDepth = parent.maxDepth;
        depth = parent.depth + 1;
        childScale = parent.childScale;
        transform.parent = parent.transform;           // set child transform to parent
        // transform.localScale = Vector3.one * childScale;

        transform.localScale = Vector3.one * Random.Range(childScale / 10, childScale * 1);
        transform.localPosition = childDirections[childIndex] * (Random.Range((0.1f + 0.1f * childScale),(0.9f + 0.9f * childScale)));
        transform.localRotation = childOrientations[childIndex];
        spawnProbability = parent.spawnProbability;
    }
    private void InitializeMaterials ()
    {
        materials = new Material[maxDepth + 1, 2];
        for (int i = 0; i <= maxDepth; i++)
        {
            float t = i / (maxDepth - 1f);
            t *= t;
            // Create a 2D array to hold color progressions
            materials[i, 0] = new Material(material);
            materials[i, 0].color = Color.Lerp(Color.gray, Color.white, t);
            materials[i, 1] = new Material(material);
            materials[i, 1].color = Color.Lerp(Color.white, Color.white, t);
        }
        // materials[maxDepth, 0].color = Color.white;
        materials[maxDepth, 1].color = Color.white;
    }
}

创建具有基于大小的重力的游戏对象

取决于重力模拟的准确性。假设模拟中的所有对象都具有相同的密度,则可以使用Mesh.bounds粗略估计它们的体积:

Vector3 size = myMesh.bounds.size;
float volume =  size.x * size.y * size.z * scale;    // scale could be childScale in your case

由于模拟是分形,因此必须在每次分形迭代中应用childScale。但是,如果网格的基础体积不变,则不必重新计算。

对于重力模拟:对于大量的对象,这可能会变得相当复杂。你必须模拟一个完整的重力场。

只计算两个相互作用的对象是相当简单的。施加在相互吸引物体上的力可以通过牛顿公式计算

F1=F2=G*m1*m2/r^2

(请参见:https://en.wikipedia.org/wiki/Gravitational_constant)

但是,在您的系统中,对象可能远远多于两个。您必须计算每个对象的上述关系——每个对象之间的关系。对于每个对象,您必须添加所有计算的力,然后应用产生的力。

假设场景中有N个对象,则必须对每个对象执行(N-1)个以上计算。这就产生了N^(N-1)计算,这将很快失控,尤其是如果你在分形结构中进行计算。

为了掌握这种巨大的复杂性,你可以引入一系列的影响,这样只有附近的物体才会相互影响。尽管这会进一步降低模拟的准确性。