Added basic robot arm controls
Added conveyor piston Fixed conveyor friction
This commit is contained in:
@@ -1,29 +1,29 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Conveyer : MonoBehaviour
|
||||
{
|
||||
public int conveyerSpeed = 0;
|
||||
public int direction = 1;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnCollisionStay(Collision collision)
|
||||
{
|
||||
// Debug-draw all contact points and normals
|
||||
foreach (ContactPoint contact in collision.contacts)
|
||||
{
|
||||
//Debug.Log(string.Format("Current Collider: {0} Position {1}", contact.otherCollider.name, contact.otherCollider.transform.position.magnitude));
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class Conveyer : MonoBehaviour
|
||||
{
|
||||
public int conveyerSpeed = 0;
|
||||
public int direction = 1;
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnCollisionStay(Collision collision)
|
||||
{
|
||||
// Debug-draw all contact points and normals
|
||||
foreach (ContactPoint contact in collision.contacts)
|
||||
{
|
||||
//Debug.Log(string.Format("Current Collider: {0} Position {1}", contact.otherCollider.name, contact.otherCollider.transform.position.magnitude));
|
||||
if(contact.otherCollider.GetComponent<Rigidbody>().velocity.magnitude < conveyerSpeed)
|
||||
{
|
||||
contact.otherCollider.GetComponent<Rigidbody>().AddForce(transform.forward * (conveyerSpeed * direction), ForceMode.Acceleration);
|
||||
contact.otherCollider.GetComponent<Rigidbody>().AddForce(transform.forward * (conveyerSpeed * direction), ForceMode.Acceleration);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
8
Assets/Scripts/Robot Arm.meta
Normal file
8
Assets/Scripts/Robot Arm.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 352da5c297e15b942a8a68621cc45617
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
250
Assets/Scripts/Robot Arm/FastIKFabric.cs
Normal file
250
Assets/Scripts/Robot Arm/FastIKFabric.cs
Normal file
@@ -0,0 +1,250 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace DitzelGames.FastIK
|
||||
{
|
||||
/// <summary>
|
||||
/// Fabrik IK Solver
|
||||
/// </summary>
|
||||
public class FastIKFabric : MonoBehaviour
|
||||
{
|
||||
/// <summary>
|
||||
/// Chain length of bones
|
||||
/// </summary>
|
||||
public int ChainLength = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Target the chain should bent to
|
||||
/// </summary>
|
||||
public Transform Target;
|
||||
public Transform Pole;
|
||||
|
||||
/// <summary>
|
||||
/// Solver iterations per update
|
||||
/// </summary>
|
||||
[Header("Solver Parameters")]
|
||||
public int Iterations = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Distance when the solver stops
|
||||
/// </summary>
|
||||
public float Delta = 0.001f;
|
||||
|
||||
/// <summary>
|
||||
/// Strength of going back to the start position.
|
||||
/// </summary>
|
||||
[Range(0, 1)]
|
||||
public float SnapBackStrength = 1f;
|
||||
|
||||
|
||||
protected float[] BonesLength; //Target to Origin
|
||||
protected float CompleteLength;
|
||||
protected Transform[] Bones;
|
||||
protected Vector3[] Positions;
|
||||
protected Vector3[] StartDirectionSucc;
|
||||
protected Quaternion[] StartRotationBone;
|
||||
protected Quaternion StartRotationTarget;
|
||||
protected Transform Root;
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Awake()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
//initial array
|
||||
Bones = new Transform[ChainLength + 1];
|
||||
Positions = new Vector3[ChainLength + 1];
|
||||
BonesLength = new float[ChainLength];
|
||||
StartDirectionSucc = new Vector3[ChainLength + 1];
|
||||
StartRotationBone = new Quaternion[ChainLength + 1];
|
||||
|
||||
//find root
|
||||
Root = transform;
|
||||
for (var i = 0; i <= ChainLength; i++)
|
||||
{
|
||||
if (Root == null)
|
||||
throw new UnityException("The chain value is longer than the ancestor chain!");
|
||||
Root = Root.parent;
|
||||
}
|
||||
|
||||
//init target
|
||||
if (Target == null)
|
||||
{
|
||||
Target = new GameObject(gameObject.name + " Target").transform;
|
||||
SetPositionRootSpace(Target, GetPositionRootSpace(transform));
|
||||
}
|
||||
StartRotationTarget = GetRotationRootSpace(Target);
|
||||
|
||||
|
||||
//init data
|
||||
var current = transform;
|
||||
CompleteLength = 0;
|
||||
for (var i = Bones.Length - 1; i >= 0; i--)
|
||||
{
|
||||
Bones[i] = current;
|
||||
StartRotationBone[i] = GetRotationRootSpace(current);
|
||||
|
||||
if (i == Bones.Length - 1)
|
||||
{
|
||||
//leaf
|
||||
StartDirectionSucc[i] = GetPositionRootSpace(Target) - GetPositionRootSpace(current);
|
||||
}
|
||||
else
|
||||
{
|
||||
//mid bone
|
||||
StartDirectionSucc[i] = GetPositionRootSpace(Bones[i + 1]) - GetPositionRootSpace(current);
|
||||
BonesLength[i] = StartDirectionSucc[i].magnitude;
|
||||
CompleteLength += BonesLength[i];
|
||||
}
|
||||
|
||||
current = current.parent;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void LateUpdate()
|
||||
{
|
||||
ResolveIK();
|
||||
}
|
||||
|
||||
private void ResolveIK()
|
||||
{
|
||||
if (Target == null)
|
||||
return;
|
||||
|
||||
if (BonesLength.Length != ChainLength)
|
||||
Init();
|
||||
|
||||
//Fabric
|
||||
|
||||
// root
|
||||
// (bone0) (bonelen 0) (bone1) (bonelen 1) (bone2)...
|
||||
// x--------------------x--------------------x---...
|
||||
|
||||
//get position
|
||||
for (int i = 0; i < Bones.Length; i++)
|
||||
Positions[i] = GetPositionRootSpace(Bones[i]);
|
||||
|
||||
var targetPosition = GetPositionRootSpace(Target);
|
||||
var targetRotation = GetRotationRootSpace(Target);
|
||||
|
||||
//1st is possible to reach?
|
||||
if ((targetPosition - GetPositionRootSpace(Bones[0])).sqrMagnitude >= CompleteLength * CompleteLength)
|
||||
{
|
||||
//just strech it
|
||||
var direction = (targetPosition - Positions[0]).normalized;
|
||||
//set everything after root
|
||||
for (int i = 1; i < Positions.Length; i++)
|
||||
Positions[i] = Positions[i - 1] + direction * BonesLength[i - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < Positions.Length - 1; i++)
|
||||
Positions[i + 1] = Vector3.Lerp(Positions[i + 1], Positions[i] + StartDirectionSucc[i], SnapBackStrength);
|
||||
|
||||
for (int iteration = 0; iteration < Iterations; iteration++)
|
||||
{
|
||||
//https://www.youtube.com/watch?v=UNoX65PRehA
|
||||
//back
|
||||
for (int i = Positions.Length - 1; i > 0; i--)
|
||||
{
|
||||
if (i == Positions.Length - 1)
|
||||
Positions[i] = targetPosition; //set it to target
|
||||
else
|
||||
Positions[i] = Positions[i + 1] + (Positions[i] - Positions[i + 1]).normalized * BonesLength[i]; //set in line on distance
|
||||
}
|
||||
|
||||
//forward
|
||||
for (int i = 1; i < Positions.Length; i++)
|
||||
Positions[i] = Positions[i - 1] + (Positions[i] - Positions[i - 1]).normalized * BonesLength[i - 1];
|
||||
|
||||
//close enough?
|
||||
if ((Positions[Positions.Length - 1] - targetPosition).sqrMagnitude < Delta * Delta)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//move towards pole
|
||||
if (Pole != null)
|
||||
{
|
||||
var polePosition = GetPositionRootSpace(Pole);
|
||||
for (int i = 1; i < Positions.Length - 1; i++)
|
||||
{
|
||||
var plane = new Plane(Positions[i + 1] - Positions[i - 1], Positions[i - 1]);
|
||||
var projectedPole = plane.ClosestPointOnPlane(polePosition);
|
||||
var projectedBone = plane.ClosestPointOnPlane(Positions[i]);
|
||||
var angle = Vector3.SignedAngle(projectedBone - Positions[i - 1], projectedPole - Positions[i - 1], plane.normal);
|
||||
Positions[i] = Quaternion.AngleAxis(angle, plane.normal) * (Positions[i] - Positions[i - 1]) + Positions[i - 1];
|
||||
}
|
||||
}
|
||||
|
||||
//set position & rotation
|
||||
for (int i = 0; i < Positions.Length; i++)
|
||||
{
|
||||
if (i == Positions.Length - 1)
|
||||
SetRotationRootSpace(Bones[i], Quaternion.Inverse(targetRotation) * StartRotationTarget * Quaternion.Inverse(StartRotationBone[i]));
|
||||
else
|
||||
SetRotationRootSpace(Bones[i], Quaternion.FromToRotation(StartDirectionSucc[i], Positions[i + 1] - Positions[i]) * Quaternion.Inverse(StartRotationBone[i]));
|
||||
SetPositionRootSpace(Bones[i], Positions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private Vector3 GetPositionRootSpace(Transform current)
|
||||
{
|
||||
if (Root == null)
|
||||
return current.position;
|
||||
else
|
||||
return Quaternion.Inverse(Root.rotation) * (current.position - Root.position);
|
||||
}
|
||||
|
||||
private void SetPositionRootSpace(Transform current, Vector3 position)
|
||||
{
|
||||
if (Root == null)
|
||||
current.position = position;
|
||||
else
|
||||
current.position = Root.rotation * position + Root.position;
|
||||
}
|
||||
|
||||
private Quaternion GetRotationRootSpace(Transform current)
|
||||
{
|
||||
//inverse(after) * before => rot: before -> after
|
||||
if (Root == null)
|
||||
return current.rotation;
|
||||
else
|
||||
return Quaternion.Inverse(current.rotation) * Root.rotation;
|
||||
}
|
||||
|
||||
private void SetRotationRootSpace(Transform current, Quaternion rotation)
|
||||
{
|
||||
if (Root == null)
|
||||
current.rotation = rotation;
|
||||
else
|
||||
current.rotation = Root.rotation * rotation;
|
||||
}
|
||||
|
||||
void OnDrawGizmos()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
var current = this.transform;
|
||||
for (int i = 0; i < ChainLength && current != null && current.parent != null; i++)
|
||||
{
|
||||
var scale = Vector3.Distance(current.position, current.parent.position) * 0.1f;
|
||||
Handles.matrix = Matrix4x4.TRS(current.position, Quaternion.FromToRotation(Vector3.up, current.parent.position - current.position), new Vector3(scale, Vector3.Distance(current.parent.position, current.position), scale));
|
||||
Handles.color = Color.green;
|
||||
Handles.DrawWireCube(Vector3.up * 0.5f, Vector3.one);
|
||||
current = current.parent;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Robot Arm/FastIKFabric.cs.meta
Normal file
11
Assets/Scripts/Robot Arm/FastIKFabric.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efa89c87015118842aedfe169a130b47
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
76
Assets/Scripts/Robot Arm/RobotArmController.cs
Normal file
76
Assets/Scripts/Robot Arm/RobotArmController.cs
Normal file
@@ -0,0 +1,76 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
public class RobotArmController : MonoBehaviour
|
||||
{
|
||||
|
||||
public GameObject target;
|
||||
public float armSpeed = 1;
|
||||
public float armRotationSpeed = 10;
|
||||
public Vector3 targetConstraints;
|
||||
public GameObject targetMarker;
|
||||
|
||||
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
targetMarker.transform.position = new Vector3(target.transform.position.x, transform.position.y + .5f, target.transform.position.z);
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void FixedUpdate()
|
||||
{
|
||||
|
||||
//Hoch/Runter
|
||||
if (Keyboard.current.ctrlKey.isPressed && target.transform.position.y > transform.position.y)
|
||||
{
|
||||
target.transform.localPosition += Vector3.down * Time.deltaTime * armSpeed;
|
||||
}
|
||||
|
||||
if (Keyboard.current.shiftKey.isPressed && target.transform.localPosition.y < targetConstraints.y)
|
||||
{
|
||||
target.transform.localPosition += Vector3.up * Time.deltaTime * armSpeed;
|
||||
}
|
||||
|
||||
//Debug.Log(-targetConstraints.z);
|
||||
//Left/Right
|
||||
if (Keyboard.current.aKey.isPressed && target.transform.localPosition.z > -targetConstraints.z)
|
||||
{
|
||||
target.transform.localPosition += Vector3.back * Time.deltaTime * armSpeed;
|
||||
}
|
||||
|
||||
if (Keyboard.current.dKey.isPressed && target.transform.localPosition.z < targetConstraints.z)
|
||||
{
|
||||
target.transform.localPosition += Vector3.forward * Time.deltaTime * armSpeed;
|
||||
}
|
||||
|
||||
//Left/Right
|
||||
if (Keyboard.current.qKey.isPressed)
|
||||
{
|
||||
transform.Rotate(0.0f, armRotationSpeed * Time.deltaTime, 0.0f, Space.Self);
|
||||
}
|
||||
|
||||
if (Keyboard.current.eKey.isPressed)
|
||||
{
|
||||
transform.Rotate(0.0f, -armRotationSpeed * Time.deltaTime, 0.0f, Space.Self);
|
||||
}
|
||||
|
||||
//Forwards/Backwards
|
||||
if (Keyboard.current.wKey.isPressed && target.transform.localPosition.x > -targetConstraints.x)
|
||||
{
|
||||
target.transform.localPosition += Vector3.left * Time.deltaTime * armSpeed;
|
||||
}
|
||||
|
||||
if (Keyboard.current.sKey.isPressed && target.transform.localPosition.x < -3.5f)
|
||||
{
|
||||
target.transform.localPosition += Vector3.right * Time.deltaTime * armSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Robot Arm/RobotArmController.cs.meta
Normal file
11
Assets/Scripts/Robot Arm/RobotArmController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: babb9069bf6a6d646a632cd5453ccf7c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user