Newer
Older
DungeonShooting / DungeonShooting_Godot / src / test / TestMask.cs
using Godot;
using System;
using System.Collections.Generic;
using System.Linq;
using Godot.Collections;

public partial class TestMask : Node2D
{
    [Export]
    public Polygon2D PolygonNode;

    public List<Vector2[]> Result = new List<Vector2[]>();
    public override void _Ready()
    {
        //Geometry2D.
        // var point = new Vector2[]
        // {
        //     new Vector2(0, 0),
        //     new Vector2(0, 500),
        //     new Vector2(500, 500),
        //     new Vector2(500, 0)
        // };
        // Result = Geometry2D.ClipPolygons(point, new Vector2[]
        // {
        //     new Vector2(20, 20),
        //     new Vector2(20, 100),
        //     new Vector2(90, 50),
        // });
        //PolygonNode.Polygon = clipPolygons[0];
    }

    public override void _Process(double delta)
    {
        //if (Input.IsActionJustPressed("fire"))
        if (Input.IsActionPressed("fire") || Input.IsActionJustPressed("roll"))
        {
            var time = DateTime.Now;
            RunTest();
            Debug.Log("用时: " + (DateTime.Now - time).TotalMilliseconds);
        }

        if (Input.IsActionJustPressed("meleeAttack"))
        {
            for (var i = 0; i < Result.Count; i++)
            {
                var temp = Result[i];
                Result[i] = StreamlineVertices3(temp, 10, Mathf.DegToRad(15));
                Debug.Log($"优化前: {temp.Length}, 优化后: {Result[i].Length}");
            }
        }

        if (Input.IsActionJustPressed("exchangeWeapon"))
        {
            Result.Clear();
        }
        QueueRedraw();
    }

    private void RunTest()
    {
        var position = GetGlobalMousePosition();
        var circle = GetCircle(position, 50, 10);
        //先检测有没有碰撞
        var flag = false;
        for (var i = 0; i < Result.Count; i++)
        {
            var p = Result[i];
            if (CollisionPolygon(p, circle))
            {
                flag = true;
                var mergePolygons = Geometry2D.MergePolygons(p, circle);
                Result.RemoveAt(i);
                for (var j = 0; j < mergePolygons.Count; j++)
                {
                    Result.Add(mergePolygons[j]);
                    //Result.Add(StreamlineVertices(mergePolygons[j], 50));
                    //Result.Add(StreamlineVertices2(mergePolygons[j], Mathf.DegToRad(5)));
                    //Result.Add(StreamlineVertices3(mergePolygons[j], 20, Mathf.DegToRad(15)));
                }
                break;
            }
        }

        if (!flag)
        {
            Result.Add(circle);
            //Result.Add(StreamlineVertices2(circle, Mathf.DegToRad(5)));
        }
    }
    
    private Vector2[] StreamlineVertices3(Vector2[] polygon, float d, float r)
    {
        if (polygon.Length <= 3)
        {
            return polygon;
        }
        
        float v = d * d;
        List<Vector2> list = new List<Vector2>();
        Vector2 tempPoint = polygon[0];
        Vector2 tempPoint2 = polygon[1];
        list.Add(tempPoint);
        float tr = tempPoint.AngleToPoint(tempPoint2);
        float delta = 0;
        for (var i = 1; i < polygon.Length; i++)
        {
            var curr = polygon[i];
            var prev = polygon[i > 0 ? i - 1 : polygon.Length - 1];
            var next = polygon[i < polygon.Length - 1 ? i + 1 : 0];
            if (prev.DistanceSquaredTo(next) > v)
            {
                //list.Add(curr);
                
                var angle = curr.AngleToPoint(next);
                delta += angle - tr;
                if (Mathf.Abs(delta) >= r)
                {
                    Debug.Log(i + ", 偏差角度: " + Mathf.RadToDeg(delta));
                    tr = angle;
                    delta = 0;
                    //var result = Geometry2D.GetClosestPointToSegmentUncapped(curr, tempPoint, tempPoint2);
                    tempPoint = curr;
                    //tempPoint2 = next;
                    list.Add(tempPoint);
                }
            }
        }

        return list.ToArray();
    }

    private bool CollisionPolygon(Vector2[] polygon1, Vector2[] polygon2)
    {
        for (int shape = 0; shape < 2; shape++)
        {
            if (shape == 1)
            {
                Vector2[] tmp = polygon1;
                polygon1 = polygon2;
                polygon2 = tmp;
            }

            for (int a = 0; a < polygon1.Length; a++)
            {
                int b = (a + 1) % polygon1.Length;
                float axisX = -(polygon1[b].Y - polygon1[a].Y);
                float axisY = polygon1[b].X - polygon1[a].X;

                float mina = float.MaxValue;
                float maxa = float.MinValue;
                for (int p = 0; p < polygon1.Length; p++)
                {
                    float t = polygon1[p].X * axisX + polygon1[p].Y * axisY;
                    mina = Math.Min(mina, t);
                    maxa = Math.Max(maxa, t);
                }

                float minb = float.MaxValue;
                float maxb = float.MinValue;
                for (int p = 0; p < polygon2.Length; p++)
                {
                    float t = polygon2[p].X * axisX + polygon2[p].Y * axisY;
                    minb = Math.Min(minb, t);
                    maxb = Math.Max(maxb, t);
                }

                if (maxa < minb || mina > maxb)
                    return false;
            }
        }

        return true;
    }

    private Vector2[] GetCircle(Vector2 position, float radius, int vertexCount)
    {
        Vector2[] vertices = new Vector2[vertexCount];

        for (int i = 0; i < vertexCount; i++)
        {
            float angle = i * 2.0f * (float)Math.PI / vertexCount;
            Vector2 vertex = position + new Vector2((float)Math.Cos(angle) * radius, (float)Math.Sin(angle) * radius);
            vertices[i] = vertex;
        }

        return vertices;
    }

    public override void _Draw()
    {
        if (Result != null)
        {
            foreach (var vector2s in Result)
            {
                var list = vector2s.ToList();
                list.Add(vector2s[0]);
                DrawPolyline(list.ToArray(), Colors.Red);
                foreach (var vector2 in list)
                {
                    DrawCircle(vector2, 2, Colors.Green);
                }
            }
            //DrawColoredPolygon(Result[1], Colors.Red);
        }
        
    }
}