rope start
This commit is contained in:
parent
692cbf4d10
commit
1cbff2800f
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a07dfdaccf053414085b41179c0ab234
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: fb42a2c8fa09c32489663226dc7167e1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e87b5185694f23a4390596cc0294bee7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 27ac133d9e10e544ba603e07122e3359
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 61cc19e8607c5c243941e77804b59b30
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
Loading…
Reference in New Issue