Newer
Older
DungeonShooting / DungeonShooting_Godot / src / test / TestMask.cs
@小李xl 小李xl on 24 Nov 2023 4 KB 调研中
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);
		}
		
	}
}