Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Godot;
- using System.Collections.Generic;
- public class Drut2D : Node2D
- {
- private class Wire
- {
- private List<Segment> segments = new List<Segment>();
- public float TotalDistance { get; private set; }
- public Wire(Segment firstSegment)
- {
- addSegment(firstSegment);
- }
- private void addSegment(Segment seg)
- {
- segments.Add(seg);
- TotalDistance += seg.TotalDistance;
- }
- public void AttachNextSegment(Vector2 offsetToMiddle, float r, float y, bool toRight)
- {
- var end = segments[segments.Count - 1].EndPoint;
- var seg = new Segment(end, end + offsetToMiddle, r, y, toRight);
- addSegment(seg);
- }
- public void Draw(CanvasItem c)
- {
- foreach (var s in segments)
- {
- s.Draw(c);
- }
- }
- public void DrawRing(CanvasItem c, float atDistance)
- {
- foreach (var s in segments)
- {
- var sd = s.TotalDistance;
- if (atDistance > sd)
- {
- atDistance -= sd;
- continue;
- }
- else
- {
- s.DrawRing(c, atDistance);
- return;
- }
- }
- }
- }
- private class Segment
- {
- private static Color color = new Color(1, 0, 0);
- private Vector2 xStart;
- private Vector2 xEnd;
- private Vector2 center;
- private float r;
- private Vector2 yStart;
- private Vector2 yEnd;
- private float startAngle;
- private float endAngle;
- private bool toRight;
- private float xDistance;
- private float arcDistance;
- private float yDistance;
- public Vector2 EndPoint => yEnd;
- public float TotalDistance => xDistance + arcDistance + yDistance;
- public Segment(Vector2 startPoint, Vector2 middlePoint, float r, float y, bool toRight = false)
- {
- this.toRight = toRight;
- // Calc the x fragment
- var direction = (middlePoint - startPoint).Normalized();
- xStart = startPoint;
- xEnd = middlePoint - direction * r;
- xDistance = (xEnd - xStart).Length();
- // Calc the arc fragment
- this.r = r;
- var perp = direction.Perpendicular();
- if (toRight)
- perp *= -1;
- center = xEnd + perp * r;
- yStart = middlePoint + perp * r;
- startAngle = (yStart - center).Angle();
- endAngle = (xEnd - center).Angle();
- if (Mathf.Abs(endAngle - startAngle) > Mathf.Pi)
- {
- if (startAngle <= 0)
- startAngle += Mathf.Pi * 2;
- if (endAngle <= 0)
- endAngle += Mathf.Pi * 2;
- }
- arcDistance = Mathf.Abs(endAngle - startAngle) * r;
- // Calc the y fragment
- yEnd = yStart + perp * y;
- yDistance = y;
- }
- public void Draw(CanvasItem c)
- {
- c.DrawLine(xStart, xEnd, color, 5);
- c.DrawArc(center, r, startAngle, endAngle, 180, color, 5);
- c.DrawLine(yStart, yEnd, color, 5);
- }
- public void DrawRing(CanvasItem c, float atDistance)
- {
- Vector2 vectorPosition;
- Vector2 ringDirection;
- if (atDistance >= xDistance + arcDistance)
- {
- // On the y fragment
- vectorPosition = VectorExtensions.Lerp(yStart, yEnd, (atDistance - xDistance - arcDistance) / yDistance);
- ringDirection = (yEnd - yStart).Normalized();
- }
- else if (atDistance > xDistance)
- {
- // On the arc
- var v = xEnd - center;
- var rotationRadians = (atDistance - xDistance) / r;
- if (!toRight)
- rotationRadians *= -1;
- v = v.Rotated(rotationRadians);
- vectorPosition = center + v;
- ringDirection = v.Perpendicular().Normalized();
- if (toRight)
- ringDirection *= -1;
- //c.DrawLine(center, xEnd, new Color(0, 0, 1));
- //c.DrawLine(center, vectorPosition, new Color(0, 1, 0));
- float centripetalForce = velocity*velocity/r;
- v = v.Normalized() * -1;
- Vector2 forceP = vectorPosition + v * (centripetalForce/velocity)*10;
- c.DrawLine(vectorPosition + v * 10, forceP, new Color(0, 0, 1), 3);
- c.DrawLine(forceP, forceP - v.Rotated(0.785f).Normalized()*10, new Color(0, 0, 1), 2);
- c.DrawLine(forceP, forceP - v.Rotated(-0.785f).Normalized()*10, new Color(0, 0, 1), 2);
- }
- else
- {
- // On the x fragment
- vectorPosition = VectorExtensions.Lerp(xStart, xEnd, atDistance / xDistance);
- ringDirection = (xEnd - xStart).Normalized();
- }
- c.DrawCircle(vectorPosition, 10, new Color(0, 1, 0));
- c.DrawLine(vectorPosition, vectorPosition+ringDirection*10, new Color(0, 0, 1), 3);
- }
- }
- private Wire wire;
- private static float velocity = 100;
- private float ringDistance;
- // Called when the node enters the scene tree for the first time.
- public override void _Ready()
- {
- wire = new Wire(new Segment(new Vector2(50, 400), new Vector2(50, 500), 50, 100));
- wire.AttachNextSegment(new Vector2(100, 0), 30, 100, false);
- wire.AttachNextSegment(new Vector2(0, -100), 60, 100, true);
- wire.AttachNextSegment(new Vector2(300, 0), 45, 100, true);
- wire.AttachNextSegment(new Vector2(0, 100), 55, 100, false);
- wire.AttachNextSegment(new Vector2(50, 0), 25, 100, false);
- wire.AttachNextSegment(new Vector2(0, -200), 40, 100, false);
- wire.AttachNextSegment(new Vector2(-775, 0), 50, 160, false);
- }
- public override void _Draw()
- {
- wire.Draw(this);
- wire.DrawRing(this, ringDistance);
- }
- // Called every frame. 'delta' is the elapsed time since the previous frame.
- public override void _Process(float delta)
- {
- Update();
- ringDistance += velocity * delta;
- if(ringDistance > wire.TotalDistance)
- {
- ringDistance %= wire.TotalDistance;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement