rope start

This commit is contained in:
Sveske Juice 2024-02-02 12:03:44 -08:00
parent 692cbf4d10
commit 1cbff2800f
10 changed files with 261 additions and 0 deletions

View File

@ -0,0 +1,15 @@
using UnityEngine;
[System.Serializable]
public class Point
{
public Vector2 position, prevPosition;
public bool locked;
public Point(Vector2 position, bool locked = false)
{
this.position = position;
this.prevPosition = position;
this.locked = locked;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a07dfdaccf053414085b41179c0ab234
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using UnityEngine;
public class Rope
{
public List<Point> points { get ; private set; }
public List<Stick> sticks { get; private set; }
public Rope(List<Point> points, List<Stick> sticks)
{
this.points = points;
this.sticks = sticks;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fb42a2c8fa09c32489663226dc7167e1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,32 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RopeBuilder
{
List<Point> points = new();
List<Stick> sticks = new();
public RopeBuilder AddPoint(Point point)
{
points.Add(point);
return this;
}
public RopeBuilder ConnectPoints(Point A, Point B)
{
sticks.Add(new Stick(A, B));
return this;
}
public RopeBuilder ConnectPoints(int idxA, int idxB)
{
sticks.Add(new Stick(points[idxA], points[idxB]));
return this;
}
public Rope Build()
{
return new Rope(points: points, sticks: sticks);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e87b5185694f23a4390596cc0294bee7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,129 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityUtils;
public class RopeSimulator : MonoBehaviour
{
[SerializeField]
private float gravity = 10;
[SerializeField]
private float solveIterations = 10;
[SerializeField]
private float constrainStickMinLength = 0.1f;
int[] order;
public Vector2 testPos;
Rope rope;
private void Start()
{
rope = new RopeBuilder()
.AddPoint(new Point(testPos, locked: true))
.AddPoint(new Point(testPos.Add(x:5f)))
.AddPoint(new Point(testPos.Add(x: 10f)))
.AddPoint(new Point(testPos.Add(x: 15f)))
.AddPoint(new Point(testPos.Add(x: 20f)))
.ConnectPoints(0, 1)
.ConnectPoints(1, 2)
.ConnectPoints(2, 3)
.ConnectPoints(3, 4)
.Build();
CreateOrderArray();
}
private void Update()
{
Simulate();
}
private void OnDrawGizmos()
{
if (!Application.isPlaying) return;
foreach (var point in rope.points)
{
Debug.Log($"pos: {point.position}");
Gizmos.DrawSphere(point.position, 1f);
}
}
void Simulate()
{
foreach (Point p in rope.points)
{
if (!p.locked)
{
Vector2 positionBeforeUpdate = p.position;
p.position += p.position - p.prevPosition;
p.position += Vector2.down * gravity * Time.deltaTime * Time.deltaTime;
p.prevPosition = positionBeforeUpdate;
}
}
for (int i = 0; i < solveIterations; i++)
{
for (int s = 0; s < rope.sticks.Count; s++)
{
Stick stick = rope.sticks[order[s]];
if (stick.dead)
{
continue;
}
Vector2 stickCentre = (stick.A.position + stick.B.position) / 2;
Vector2 stickDir = (stick.A.position - stick.B.position).normalized;
float length = (stick.A.position - stick.B.position).magnitude;
if (length > stick.length || length > constrainStickMinLength)
{
if (!stick.A.locked)
{
stick.A.position = stickCentre + stickDir * stick.length / 2;
}
if (!stick.B.locked)
{
stick.B.position = stickCentre - stickDir * stick.length / 2;
}
}
}
}
}
void CreateOrderArray()
{
order = new int[rope.sticks.Count];
for (int i = 0; i < order.Length; i++)
{
order[i] = i;
}
ShuffleArray(order, new System.Random());
}
public static T[] ShuffleArray<T>(T[] array, System.Random prng)
{
int elementsRemainingToShuffle = array.Length;
int randomIndex = 0;
while (elementsRemainingToShuffle > 1)
{
// Choose a random element from array
randomIndex = prng.Next(0, elementsRemainingToShuffle);
T chosenElement = array[randomIndex];
// Swap the randomly chosen element with the last unshuffled element in the array
elementsRemainingToShuffle--;
array[randomIndex] = array[elementsRemainingToShuffle];
array[elementsRemainingToShuffle] = chosenElement;
}
return array;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 27ac133d9e10e544ba603e07122e3359
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,16 @@
using UnityEngine;
[System.Serializable]
public class Stick
{
public Point A, B;
public float length;
public bool dead;
public Stick(Point pointA, Point pointB)
{
this.A = pointA;
this.B = pointB;
length = Vector2.Distance(pointA.position, pointB.position);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 61cc19e8607c5c243941e77804b59b30
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: