1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
using UnityEngine;
//Code is taken from UMod
public class PhysGun : MonoBehaviour
{
[SerializeField]
private float _maxGrabDistance = 40f;
[SerializeField]
private float _minGrabDistance = 1f;
[SerializeField]
private LineRenderer _pickLine;
[SerializeField]
private Transform _barrelPoint;
private Rigidbody _grabbedObject;
private float _pickDistance;
private Vector3 _pickOffset;
private Vector3 _pickTargetPosition;
private Vector3 _pickForce;
private void Start()
{
if (!_barrelPoint)
{
_barrelPoint = transform;
}
if (!_pickLine)
{
var obj = new GameObject("PhysGun Pick Line");
_pickLine = obj.AddComponent<LineRenderer>();
_pickLine.startWidth = 0.02f;
_pickLine.endWidth = 0.02f;
_pickLine.useWorldSpace = true;
_pickLine.gameObject.SetActive(false);
}
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
{
Grab();
}
if (Input.GetKeyUp(KeyCode.Mouse0))
{
if (_grabbedObject)
{
Release();
}
}
if (Input.GetKeyDown(KeyCode.Mouse1))
{
if (_grabbedObject)
{
Release(true);
}
}
_pickDistance = Mathf.Clamp(_pickDistance + Input.mouseScrollDelta.y, _minGrabDistance, _maxGrabDistance);
}
private void LateUpdate()
{
if (_grabbedObject)
{
var midpoint = (transform.position + _pickTargetPosition) / 2f;
midpoint += Vector3.ClampMagnitude(_pickForce / 2f, 1f);
DrawQuadraticBezierCurve(_pickLine, _barrelPoint.position, midpoint, _grabbedObject.worldCenterOfMass - _pickOffset);
}
}
private void FixedUpdate()
{
if (_grabbedObject != null)
{
var ray = Camera.main.ViewportPointToRay(Vector3.one * .5f);
_pickTargetPosition = (ray.origin + ray.direction * _pickDistance) + _pickOffset;
var forceDir = _pickTargetPosition - _grabbedObject.position;
_pickForce = forceDir / Time.fixedDeltaTime * 0.3f / _grabbedObject.mass;
_grabbedObject.velocity = _pickForce;
}
}
private void Grab()
{
var ray = Camera.main.ViewportPointToRay(Vector3.one * .5f);
if(Physics.Raycast(ray, out RaycastHit hit, _maxGrabDistance)
&& hit.rigidbody != null)
{
_pickOffset = hit.rigidbody.worldCenterOfMass - hit.point;
_pickDistance = hit.distance;
_grabbedObject = hit.rigidbody;
_grabbedObject.collisionDetectionMode = CollisionDetectionMode.Continuous;
_grabbedObject.useGravity = false;
_grabbedObject.freezeRotation = true;
_grabbedObject.isKinematic = false;
_pickLine.gameObject.SetActive(true);
}
}
private void Release(bool setKinematic = false)
{
_grabbedObject.collisionDetectionMode = CollisionDetectionMode.Discrete;
_grabbedObject.useGravity = true;
_grabbedObject.freezeRotation = false;
_grabbedObject.isKinematic = setKinematic;
_grabbedObject = null;
_pickLine.gameObject.SetActive(false);
}
// https://www.codinblack.com/how-to-draw-lines-circles-or-anything-else-using-linerenderer/
void DrawQuadraticBezierCurve(LineRenderer line, Vector3 point0, Vector3 point1, Vector3 point2)
{
line.positionCount = 10;
float t = 0f;
Vector3 B = new Vector3(0, 0, 0);
for (int i = 0; i < line.positionCount; i++)
{
B = (1 - t) * (1 - t) * point0 + 2 * (1 - t) * t * point1 + t * t * point2;
line.SetPosition(i, B);
t += (1 / (float)line.positionCount);
}
}
}
|