C# 使用统一的碰撞器将圆形精灵分割成彩色碎片

C# 使用统一的碰撞器将圆形精灵分割成彩色碎片,c#,unity3d,C#,Unity3d,我有一个统一的旋转圆精灵 private void Update() { transform.Rotate(0, 0, 10 * Time.deltaTime); } 在我的Start方法中,我想把这个精灵分成几个部分。我输入了一个颜色数组作为参数 private void SetColors(Color[] colors) { // divide into color pieces } 例如,我在红色、蓝色、绿色、黄色中传递,圆圈应如下所示 可能的颜色数量是无限的 圆圈本

我有一个统一的旋转圆精灵

private void Update()
{
    transform.Rotate(0, 0, 10 * Time.deltaTime);
}
在我的
Start
方法中,我想把这个精灵分成几个部分。我输入了一个颜色数组作为参数

private void SetColors(Color[] colors)
{
    // divide into color pieces
}
例如,我在红色、蓝色、绿色、黄色中传递,圆圈应如下所示

可能的颜色数量是无限的

圆圈本身有一个圆圈触发器。当检测触发碰撞时,我想检测碰撞的颜色

private void OnTriggerEnter2D(Collider2D col)
{
    if (col.gameObject == ball)
    {
        // Color hitColor = the color that was hit
    }
}
可以用一个简单的圆形精灵吗

更新:

如果我说当圆被什么东西击中时,它总是在圆的顶部,那么这个问题可能更容易解决


我可能会使用一段时间内的旋转速度来计算当前的点击颜色。

可能有点晚,但我发现这个问题非常复杂:

此组件放置在
画布中的空
游戏对象上。它负责创建和更新分段(并使用圆碰撞器控制光标对象)


演示

图像
预制件上的设置


由于默认的
旋钮
纹理,看起来很糟糕。。您应该使用质量更好的圆形纹理。

我唯一能想到的就是利用并获得碰撞点处像素的颜色。但是,您需要使用碰撞器而不是触发器来执行此操作。话虽如此,但没有深入探讨,我认为最普通的方法就是为圆圈的每一部分实例化一个游戏对象。你想要这个答案的哪一部分:制作一个普通的圆圈精灵,让它被代码分割并自动着色,或者根据圆圈的哪一部分被触摸来获取对应的颜色?我需要这两个部分。我想给圆上色,我想得到碰撞检测。但我会更新我的问题
public class CircleController : MonoBehaviour
{
    public RectTransform rectTransform;

    public List<Color> InitialColors = new List<Color>();


    private List<Circlesegment> segments = new List<Circlesegment>();

    public Circlesegment circleSeggmentPrefab;

    public float firstSegmentAngleOffset = 0f;

    // maximum vertices to use for the circle
    // equally spread over all segments so not always uses all of them
    public int totalMaxVertices = 50;

    private void Awake()
    {
        rectTransform = GetComponent<RectTransform>();

        // if 0 start first segment at top
        var startAngle = firstSegmentAngleOffset;
        var anglePerSegment = 360f / InitialColors.Count;
        var verticesPerSegment = totalMaxVertices / InitialColors.Count;

        foreach (var initialColor in InitialColors)
        {
            var segment = Instantiate(circleSeggmentPrefab, transform);
            segment.Initialize(this, initialColor, verticesPerSegment, rectTransform.rect.width / 2f, startAngle, anglePerSegment);

            segments.Add(segment);

            startAngle += anglePerSegment;
        }
    }

    // Used this to simulate the collisions using the mouse
    private CircleCollider2D cursor;

    //used this to simulate the collision using mouse
    private void Update()
    {
        if (!cursor)
        {
            cursor = new GameObject("cursor simulator", typeof(CircleCollider2D)).GetComponent<CircleCollider2D>();
            cursor.radius = 10;
            cursor.enabled = false;
        }

        cursor.transform.position = Input.mousePosition;

        if (Input.GetMouseButtonDown(0))
        {
            cursor.enabled = true;
        }
        else if (Input.GetMouseButtonUp(0))
        {
            cursor.enabled = false;
        }
    }

    public void RemoveSegment(Circlesegment segment)
    {
        segments.Remove(segment);
        Destroy(segment.gameObject);

        if (segments.Count == 0)
        {
            Debug.Log("GameOver!");
            return;
        }

        var startAngle = firstSegmentAngleOffset;
        var anglePerSegment = 360f / segments.Count;
        var verticesPerSegment = totalMaxVertices / segments.Count;

        foreach (var circleSegment in segments)
        {
            circleSegment.AnimateTowards(verticesPerSegment, startAngle, anglePerSegment);

            startAngle += anglePerSegment;
        }
    }
}
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(EdgeCollider2D))]
[RequireComponent(typeof(Image))]
public class Circlesegment : MonoBehaviour
{
    [SerializeField] Image image;
    [SerializeField] EdgeCollider2D collider;
    [SerializeField] Rigidbody2D rigidBody;
    [SerializeField] RectTransform rectTransform;

    [SerializeField] private int _segments;
    [SerializeField] private float _startAngle;
    [SerializeField] private float _segmentAngle;

    private float _radius;
    private CircleController circleController;

    public Color Color;

    private void OnCollisionEnter2D(Collision2D other)
    {
        circleController.RemoveSegment(this);
    }

    public void Initialize(CircleController controller, Color color, int segments, float radius, float startAngle, float segmentAngle)
    {
        Color = color;
        circleController = controller;
        _radius = radius;

        if (!image) image = GetComponent<Image>();
        if (!collider) collider = GetComponent<EdgeCollider2D>();
        if (!rigidBody) rigidBody = GetComponent<Rigidbody2D>();
        if (!rectTransform) rectTransform = GetComponent<RectTransform>();

        image.color = color;
        rectTransform.sizeDelta = new Vector2(radius * 2, radius * 2);

        UpdateSegment(segments, startAngle, segmentAngle);
    }

    public void AnimateTowards(int segments, float startAngle, float segmentAngle, float duration = 1f)
    {
        StopAllCoroutines();

        StartCoroutine(AnimateTowardsroutine(segments, startAngle, segmentAngle, duration));
    }

    private IEnumerator AnimateTowardsroutine(int segments, float startAngle, float segmentAngle, float duration)
    {
        var timePassed = 0f;
        var currentStartAngle = _startAngle;
        var currentSegmentAngle = _segmentAngle;

        while (timePassed <= duration)
        {
            var lerpFactor = timePassed / duration;

            UpdateSegment(segments, Mathf.LerpAngle(currentStartAngle, startAngle, lerpFactor), Mathf.LerpAngle(currentSegmentAngle, segmentAngle, lerpFactor));

            timePassed += Mathf.Min(duration - timePassed, Time.deltaTime);
            yield return null;
        }

        UpdateSegment(segments, startAngle, segmentAngle);
    }

    public void UpdateSegment(int segments, float startAngle, float segmentAngle)
    {
        _segments = segments;
        _startAngle = startAngle;
        _segmentAngle = segmentAngle;

        var arcPoints = new List<Vector2>();
        var angle = 0f;
        var arcLength = segmentAngle;

        if (!Mathf.Approximately(Mathf.Abs(segmentAngle), 360)) arcPoints.Add(Vector2.zero);

        // calculate procedural circle vertices
        for (var i = 0; i <= segments; i++)
        {
            var x = Mathf.Sin(Mathf.Deg2Rad * angle) * _radius;
            var y = Mathf.Cos(Mathf.Deg2Rad * angle) * _radius;

            arcPoints.Add(new Vector2(x, y));

            angle += (arcLength / segments);
        }

        if (!Mathf.Approximately(Mathf.Abs(segmentAngle), 360)) arcPoints.Add(Vector2.zero);

        image.fillAmount = arcLength / 360f;
        rigidBody.rotation = startAngle;
        collider.points = arcPoints.ToArray();
    }

    // For testing
    [ContextMenu("UpdateSegment")]
    private void UpdateSegment()
    {
        UpdateSegment(_segments, _startAngle, _segmentAngle);
    }

    //For testing
    [ContextMenu("AnimateTowards")]
    private void AnimateTowards()
    {
        AnimateTowards(_segments, _startAngle, _segmentAngle);
    }
}