@quenty/ik 6.2.1-canary.256.edbbcfc.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/LICENSE.md +1 -1
- package/package.json +19 -18
- package/src/Client/Rig/IKRigAimerLocalPlayer.lua +59 -11
- package/src/Client/Rig/IKRigClient.lua +27 -6
- package/src/Server/Rig/IKRig.lua +1 -0
- package/src/Shared/Arm/ArmIKBase.lua +124 -17
- package/src/Shared/Arm/ArmIKBase.story.lua +47 -0
- package/src/Shared/Rig/IKRigBase.lua +9 -1
- package/test/default.project.json +3 -11
- package/test/scripts/Client/ClientMain.client.lua +4 -4
- package/test/scripts/Server/ServerMain.server.lua +14 -6
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
# [7.0.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ik@6.3.0...@quenty/ik@7.0.0) (2022-05-21)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Add new IK (without actual math for now), and improve replication rates among other things ([766f358](https://github.com/Quenty/NevermoreEngine/commit/766f35801576f56cc3b1372ee88e8bb9525058ff))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [6.3.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/ik@6.2.0...@quenty/ik@6.3.0) (2022-03-27)
|
|
7
18
|
|
|
8
19
|
**Note:** Version bump only for package @quenty/ik
|
|
9
20
|
|
package/LICENSE.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quenty/ik",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.0",
|
|
4
4
|
"description": "Inverse Kinematics for characters on Roblox",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"Roblox",
|
|
@@ -26,27 +26,28 @@
|
|
|
26
26
|
"Quenty"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@quenty/acceltween": "2.
|
|
30
|
-
"@quenty/baseobject": "
|
|
31
|
-
"@quenty/binder": "
|
|
32
|
-
"@quenty/camera": "
|
|
33
|
-
"@quenty/characterutils": "
|
|
34
|
-
"@quenty/humanoidtracker": "
|
|
35
|
-
"@quenty/loader": "
|
|
36
|
-
"@quenty/maid": "2.
|
|
37
|
-
"@quenty/math": "2.
|
|
38
|
-
"@quenty/promise": "
|
|
39
|
-
"@quenty/
|
|
40
|
-
"@quenty/
|
|
41
|
-
"@quenty/
|
|
42
|
-
"@quenty/
|
|
43
|
-
"@quenty/
|
|
29
|
+
"@quenty/acceltween": "^2.2.0",
|
|
30
|
+
"@quenty/baseobject": "^5.0.0",
|
|
31
|
+
"@quenty/binder": "^6.0.0",
|
|
32
|
+
"@quenty/camera": "^7.0.0",
|
|
33
|
+
"@quenty/characterutils": "^5.0.0",
|
|
34
|
+
"@quenty/humanoidtracker": "^5.0.0",
|
|
35
|
+
"@quenty/loader": "^5.0.0",
|
|
36
|
+
"@quenty/maid": "^2.3.0",
|
|
37
|
+
"@quenty/math": "^2.2.0",
|
|
38
|
+
"@quenty/promise": "^5.0.0",
|
|
39
|
+
"@quenty/qframe": "^5.0.0",
|
|
40
|
+
"@quenty/ragdoll": "^7.0.0",
|
|
41
|
+
"@quenty/remoting": "^5.0.0",
|
|
42
|
+
"@quenty/servicebag": "^5.0.0",
|
|
43
|
+
"@quenty/signal": "^2.2.0",
|
|
44
|
+
"@quenty/table": "^3.0.0"
|
|
44
45
|
},
|
|
45
46
|
"devDependencies": {
|
|
46
|
-
"@quenty/rigbuilderutils": "
|
|
47
|
+
"@quenty/rigbuilderutils": "^5.0.0"
|
|
47
48
|
},
|
|
48
49
|
"publishConfig": {
|
|
49
50
|
"access": "public"
|
|
50
51
|
},
|
|
51
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "9f7eaea7543c33c89d2e32c38491b13f9271f4f7"
|
|
52
53
|
}
|
|
@@ -13,7 +13,7 @@ local CameraStackService = require("CameraStackService")
|
|
|
13
13
|
local IKAimPositionPriorites = require("IKAimPositionPriorites")
|
|
14
14
|
|
|
15
15
|
local MAX_AGE_FOR_AIM_DATA = 0.2
|
|
16
|
-
local
|
|
16
|
+
local DEFAULT_REPLICATION_RATE = 1.3
|
|
17
17
|
|
|
18
18
|
local IKRigAimerLocalPlayer = setmetatable({}, BaseObject)
|
|
19
19
|
IKRigAimerLocalPlayer.ClassName = "IKRigAimerLocalPlayer"
|
|
@@ -25,24 +25,37 @@ IKRigAimerLocalPlayer.__index = IKRigAimerLocalPlayer
|
|
|
25
25
|
|
|
26
26
|
@param serviceBag ServiceBag
|
|
27
27
|
@param ikRig IKRigClient
|
|
28
|
-
@param remoteEvent RemoteEvent
|
|
29
28
|
@return IKRigAimerLocalPlayer
|
|
30
29
|
]=]
|
|
31
|
-
function IKRigAimerLocalPlayer.new(serviceBag, ikRig
|
|
30
|
+
function IKRigAimerLocalPlayer.new(serviceBag, ikRig)
|
|
32
31
|
local self = setmetatable(BaseObject.new(), IKRigAimerLocalPlayer)
|
|
33
32
|
|
|
34
33
|
self._cameraStackService = serviceBag:GetService(CameraStackService)
|
|
35
|
-
self._remoteEvent = remoteEvent or error("No remoteEvent")
|
|
36
34
|
self._ikRig = ikRig or error("No ikRig")
|
|
37
35
|
|
|
38
36
|
self._lastUpdate = 0
|
|
39
37
|
self._lastReplication = 0
|
|
40
|
-
self._aimData = nil
|
|
41
38
|
self._lookAround = true
|
|
42
39
|
|
|
40
|
+
self._aimData = nil
|
|
41
|
+
|
|
42
|
+
self._replicationRate = DEFAULT_REPLICATION_RATE
|
|
43
|
+
self._replicationRates = {}
|
|
44
|
+
|
|
43
45
|
return self
|
|
44
46
|
end
|
|
45
47
|
|
|
48
|
+
--[=[
|
|
49
|
+
Sets the remote event for replication
|
|
50
|
+
|
|
51
|
+
@param remoteEvent RemoteEvent
|
|
52
|
+
]=]
|
|
53
|
+
function IKRigAimerLocalPlayer:SetRemoteEvent(remoteEvent)
|
|
54
|
+
assert(not self._remoteEvent, "Already have remoteEvent")
|
|
55
|
+
|
|
56
|
+
self._remoteEvent = assert(remoteEvent, "No remoteEvent")
|
|
57
|
+
end
|
|
58
|
+
|
|
46
59
|
--[=[
|
|
47
60
|
Sets whether the local player should look around automatically.
|
|
48
61
|
@param lookAround boolean
|
|
@@ -75,11 +88,46 @@ function IKRigAimerLocalPlayer:SetAimPosition(position, optionalPriority)
|
|
|
75
88
|
}
|
|
76
89
|
end
|
|
77
90
|
|
|
91
|
+
function IKRigAimerLocalPlayer:PushReplicationRate(replicateRate)
|
|
92
|
+
assert(type(replicateRate) == "number", "Bad replicateRate")
|
|
93
|
+
|
|
94
|
+
local data = {
|
|
95
|
+
replicateRate = replicateRate;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
table.insert(self._replicationRates, data)
|
|
99
|
+
self:_updateReplicationRate()
|
|
100
|
+
|
|
101
|
+
if #self._replicationRates >= 10 then
|
|
102
|
+
warn("[IKRigAimerLocalPlayer] - More than 10 replication rates stored, memory leak possible")
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
return function()
|
|
106
|
+
local index = table.find(self._replicationRates, data)
|
|
107
|
+
if index then
|
|
108
|
+
table.remove(self._replicationRates, index)
|
|
109
|
+
self:_updateReplicationRate()
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
function IKRigAimerLocalPlayer:_updateReplicationRate()
|
|
115
|
+
local best = nil
|
|
116
|
+
for _, rateData in pairs(self._replicationRates) do
|
|
117
|
+
local rate = rateData.replicateRate
|
|
118
|
+
if not best or rate < best then
|
|
119
|
+
best = rate
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
self._replicationRate = best or DEFAULT_REPLICATION_RATE
|
|
124
|
+
end
|
|
125
|
+
|
|
78
126
|
--[=[
|
|
79
|
-
Gets the current aim
|
|
127
|
+
Gets the current aim position.
|
|
80
128
|
@return Vector3?
|
|
81
129
|
]=]
|
|
82
|
-
function IKRigAimerLocalPlayer:
|
|
130
|
+
function IKRigAimerLocalPlayer:GetAimPosition()
|
|
83
131
|
if self._aimData and (os.clock() - self._aimData.timeStamp) < MAX_AGE_FOR_AIM_DATA then
|
|
84
132
|
-- If we have aim data within the last 0.2 seconds start pointing at that
|
|
85
133
|
return self._aimData.position -- May be nil
|
|
@@ -121,18 +169,18 @@ function IKRigAimerLocalPlayer:UpdateStepped()
|
|
|
121
169
|
return
|
|
122
170
|
end
|
|
123
171
|
|
|
124
|
-
local
|
|
172
|
+
local aimPosition = self:GetAimPosition()
|
|
125
173
|
|
|
126
174
|
self._lastUpdate = os.clock()
|
|
127
175
|
local torso = self._ikRig:GetTorso()
|
|
128
176
|
if torso then
|
|
129
|
-
torso:Point(
|
|
177
|
+
torso:Point(aimPosition)
|
|
130
178
|
end
|
|
131
179
|
|
|
132
180
|
-- Filter replicate
|
|
133
|
-
if (os.clock() - self._lastReplication) >
|
|
181
|
+
if self._remoteEvent and (os.clock() - self._lastReplication) > self._replicationRate then
|
|
134
182
|
self._lastReplication = os.clock()
|
|
135
|
-
self._remoteEvent:FireServer(
|
|
183
|
+
self._remoteEvent:FireServer(aimPosition)
|
|
136
184
|
end
|
|
137
185
|
end
|
|
138
186
|
|
|
@@ -22,14 +22,19 @@ function IKRigClient.new(humanoid, serviceBag)
|
|
|
22
22
|
|
|
23
23
|
self._serviceBag = assert(serviceBag, "No serviceBag")
|
|
24
24
|
|
|
25
|
+
if self:GetPlayer() == Players.LocalPlayer then
|
|
26
|
+
self:_setupLocalPlayer(self._remoteEvent)
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
self:PromiseRemoteEvent():Then(function(remoteEvent)
|
|
26
|
-
self._remoteEvent = remoteEvent
|
|
30
|
+
self._remoteEvent = assert(remoteEvent, "No remoteEvent")
|
|
31
|
+
|
|
27
32
|
self._maid:GiveTask(self._remoteEvent.OnClientEvent:Connect(function(...)
|
|
28
33
|
self:_handleRemoteEventClient(...)
|
|
29
34
|
end))
|
|
30
35
|
|
|
31
|
-
if self
|
|
32
|
-
self:
|
|
36
|
+
if self._localPlayerAimer then
|
|
37
|
+
self._localPlayerAimer:SetRemoteEvent(self._remoteEvent)
|
|
33
38
|
end
|
|
34
39
|
end)
|
|
35
40
|
|
|
@@ -56,9 +61,23 @@ end
|
|
|
56
61
|
@return IKRigAimerLocalPlayer?
|
|
57
62
|
]=]
|
|
58
63
|
function IKRigClient:GetLocalPlayerAimer()
|
|
59
|
-
return self.
|
|
64
|
+
return self._localPlayerAimer
|
|
60
65
|
end
|
|
61
66
|
|
|
67
|
+
--[=[
|
|
68
|
+
Returns where the rig is looking at
|
|
69
|
+
|
|
70
|
+
@return Vector3?
|
|
71
|
+
]=]
|
|
72
|
+
function IKRigClient:GetTarget()
|
|
73
|
+
if self._localPlayerAimer then
|
|
74
|
+
return self._localPlayerAimer:GetAimPosition()
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
return self._target
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
|
|
62
81
|
function IKRigClient:_handleRemoteEventClient(newTarget)
|
|
63
82
|
assert(typeof(newTarget) == "Vector3" or newTarget == nil, "Bad newTarget")
|
|
64
83
|
|
|
@@ -67,11 +86,13 @@ function IKRigClient:_handleRemoteEventClient(newTarget)
|
|
|
67
86
|
if torso then
|
|
68
87
|
torso:Point(newTarget)
|
|
69
88
|
end
|
|
89
|
+
|
|
90
|
+
self._target = newTarget
|
|
70
91
|
end
|
|
71
92
|
|
|
72
93
|
function IKRigClient:_setupLocalPlayer(remoteEvent)
|
|
73
|
-
self.
|
|
74
|
-
self._maid:GiveTask(self.
|
|
94
|
+
self._localPlayerAimer = IKRigAimerLocalPlayer.new(self._serviceBag, self, remoteEvent)
|
|
95
|
+
self._maid:GiveTask(self._localPlayerAimer)
|
|
75
96
|
end
|
|
76
97
|
|
|
77
98
|
return IKRigClient
|
package/src/Server/Rig/IKRig.lua
CHANGED
|
@@ -21,6 +21,7 @@ function IKRig.new(humanoid)
|
|
|
21
21
|
|
|
22
22
|
self._remoteEvent = Instance.new("RemoteEvent")
|
|
23
23
|
self._remoteEvent.Name = IKConstants.REMOTE_EVENT_NAME
|
|
24
|
+
self._remoteEvent.Archivable = false
|
|
24
25
|
self._remoteEvent.Parent = self._obj
|
|
25
26
|
self._maid:GiveTask(self._remoteEvent)
|
|
26
27
|
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
local require = require(script.Parent.loader).load(script)
|
|
7
7
|
|
|
8
|
+
local RunService = game:GetService("RunService")
|
|
9
|
+
|
|
8
10
|
local BaseObject = require("BaseObject")
|
|
9
11
|
local IKAimPositionPriorites = require("IKAimPositionPriorites")
|
|
10
12
|
local IKResource = require("IKResource")
|
|
@@ -12,8 +14,11 @@ local IKResourceUtils = require("IKResourceUtils")
|
|
|
12
14
|
local Maid = require("Maid")
|
|
13
15
|
local Math = require("Math")
|
|
14
16
|
local RagdollConstants = require("RagdollConstants")
|
|
17
|
+
local LimbIKUtils = require("LimbIKUtils")
|
|
18
|
+
local QFrame = require("QFrame")
|
|
15
19
|
|
|
16
20
|
local CFA_90X = CFrame.Angles(math.pi/2, 0, 0)
|
|
21
|
+
local USE_OLD_IK_SYSTEM = false
|
|
17
22
|
|
|
18
23
|
local ArmIKBase = setmetatable({}, BaseObject)
|
|
19
24
|
ArmIKBase.ClassName = "ArmIKBase"
|
|
@@ -26,10 +31,28 @@ function ArmIKBase.new(humanoid, armName)
|
|
|
26
31
|
|
|
27
32
|
self._grips = {}
|
|
28
33
|
|
|
34
|
+
if armName == "Left" then
|
|
35
|
+
self._direction = 1
|
|
36
|
+
elseif armName == "Right" then
|
|
37
|
+
self._direction = -1
|
|
38
|
+
else
|
|
39
|
+
error("Bad arm")
|
|
40
|
+
end
|
|
41
|
+
|
|
29
42
|
self._resources = IKResource.new(IKResourceUtils.createResource({
|
|
30
43
|
name = "Character";
|
|
31
44
|
robloxName = self._humanoid.Parent.Name;
|
|
32
45
|
children = {
|
|
46
|
+
IKResourceUtils.createResource({
|
|
47
|
+
name = "UpperTorso";
|
|
48
|
+
robloxName = "UpperTorso";
|
|
49
|
+
children = {
|
|
50
|
+
IKResourceUtils.createResource({
|
|
51
|
+
name = "UpperTorsoShoulderRigAttachment";
|
|
52
|
+
robloxName = armName .. "ShoulderRigAttachment";
|
|
53
|
+
});
|
|
54
|
+
};
|
|
55
|
+
});
|
|
33
56
|
IKResourceUtils.createResource({
|
|
34
57
|
name = "UpperArm";
|
|
35
58
|
robloxName = armName .. "UpperArm";
|
|
@@ -38,6 +61,14 @@ function ArmIKBase.new(humanoid, armName)
|
|
|
38
61
|
name = "Shoulder";
|
|
39
62
|
robloxName = armName .. "Shoulder";
|
|
40
63
|
});
|
|
64
|
+
IKResourceUtils.createResource({
|
|
65
|
+
name = "UpperArmShoulderRigAttachment";
|
|
66
|
+
robloxName = armName .. "ShoulderRigAttachment";
|
|
67
|
+
});
|
|
68
|
+
IKResourceUtils.createResource({
|
|
69
|
+
name = "UpperArmElbowRigAttachment";
|
|
70
|
+
robloxName = armName .. "ElbowRigAttachment";
|
|
71
|
+
});
|
|
41
72
|
};
|
|
42
73
|
});
|
|
43
74
|
IKResourceUtils.createResource({
|
|
@@ -48,6 +79,14 @@ function ArmIKBase.new(humanoid, armName)
|
|
|
48
79
|
name = "Elbow";
|
|
49
80
|
robloxName = armName .. "Elbow";
|
|
50
81
|
});
|
|
82
|
+
IKResourceUtils.createResource({
|
|
83
|
+
name = "LowerArmElbowRigAttachment";
|
|
84
|
+
robloxName = armName .. "ElbowRigAttachment";
|
|
85
|
+
});
|
|
86
|
+
IKResourceUtils.createResource({
|
|
87
|
+
name = "LowerArmWristRigAttachment";
|
|
88
|
+
robloxName = armName .. "WristRigAttachment";
|
|
89
|
+
});
|
|
51
90
|
};
|
|
52
91
|
});
|
|
53
92
|
IKResourceUtils.createResource({
|
|
@@ -58,6 +97,10 @@ function ArmIKBase.new(humanoid, armName)
|
|
|
58
97
|
name = "Wrist";
|
|
59
98
|
robloxName = armName .. "Wrist";
|
|
60
99
|
});
|
|
100
|
+
IKResourceUtils.createResource({
|
|
101
|
+
name = "HandWristRigAttachment";
|
|
102
|
+
robloxName = armName .. "WristRigAttachment";
|
|
103
|
+
});
|
|
61
104
|
IKResourceUtils.createResource({
|
|
62
105
|
name = "HandGripAttachment";
|
|
63
106
|
robloxName = armName .. "GripAttachment";
|
|
@@ -66,6 +109,7 @@ function ArmIKBase.new(humanoid, armName)
|
|
|
66
109
|
});
|
|
67
110
|
}
|
|
68
111
|
}))
|
|
112
|
+
|
|
69
113
|
self._maid:GiveTask(self._resources)
|
|
70
114
|
self._resources:SetInstance(self._humanoid.Parent or error("No humanoid.Parent"))
|
|
71
115
|
|
|
@@ -120,7 +164,7 @@ function ArmIKBase:UpdateTransformOnly()
|
|
|
120
164
|
if not self._grips[1] then
|
|
121
165
|
return
|
|
122
166
|
end
|
|
123
|
-
if not self._shoulderTransform
|
|
167
|
+
if not (self._shoulderTransform and self._elbowTransform and self._wristTransform) then
|
|
124
168
|
return
|
|
125
169
|
end
|
|
126
170
|
if not self._resources:IsReady() then
|
|
@@ -129,33 +173,56 @@ function ArmIKBase:UpdateTransformOnly()
|
|
|
129
173
|
|
|
130
174
|
local shoulder = self._resources:Get("Shoulder")
|
|
131
175
|
local elbow = self._resources:Get("Elbow")
|
|
176
|
+
local wrist = self._resources:Get("Wrist")
|
|
132
177
|
|
|
133
|
-
|
|
134
|
-
|
|
178
|
+
if RunService:IsRunning() then
|
|
179
|
+
shoulder.Transform = self._shoulderTransform
|
|
180
|
+
elbow.Transform = self._elbowTransform
|
|
181
|
+
wrist.Transform = self._wristTransform
|
|
182
|
+
else
|
|
183
|
+
-- Test mode/story mode
|
|
184
|
+
if not self._initTest then
|
|
185
|
+
self._initTest = true
|
|
186
|
+
self._testDefaultShoulderC0 = shoulder.C0
|
|
187
|
+
self._testDefaultElbowC0 = elbow.C0
|
|
188
|
+
self._testDefaultWristC0 = wrist.C0
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
shoulder.C0 = self._testDefaultShoulderC0 * self._shoulderTransform
|
|
192
|
+
elbow.C0 = self._testDefaultElbowC0 * self._elbowTransform
|
|
193
|
+
wrist.C0 = self._testDefaultWristC0 * self._wristTransform
|
|
194
|
+
end
|
|
135
195
|
end
|
|
136
196
|
|
|
137
197
|
function ArmIKBase:Update()
|
|
138
|
-
if
|
|
139
|
-
|
|
140
|
-
|
|
198
|
+
if USE_OLD_IK_SYSTEM then
|
|
199
|
+
if self:_oldUpdatePoint() then
|
|
200
|
+
local shoulderXAngle = self._shoulderXAngle
|
|
201
|
+
local elbowXAngle = self._elbowXAngle
|
|
141
202
|
|
|
142
|
-
|
|
203
|
+
local yrot = CFrame.new(Vector3.new(), self._offset)
|
|
143
204
|
|
|
144
|
-
|
|
145
|
-
|
|
205
|
+
self._shoulderTransform = (yrot * CFA_90X * CFrame.Angles(shoulderXAngle, 0, 0)) --:inverse()
|
|
206
|
+
self._elbowTransform = CFrame.Angles(elbowXAngle, 0, 0)
|
|
207
|
+
self._wristTransform = CFrame.new()
|
|
146
208
|
|
|
147
|
-
|
|
209
|
+
self:UpdateTransformOnly()
|
|
210
|
+
end
|
|
211
|
+
else
|
|
212
|
+
if self:_newUpdate() then
|
|
213
|
+
self:UpdateTransformOnly()
|
|
214
|
+
end
|
|
148
215
|
end
|
|
149
216
|
end
|
|
150
217
|
|
|
151
|
-
function ArmIKBase:
|
|
218
|
+
function ArmIKBase:_oldUpdatePoint()
|
|
152
219
|
local grip = self._grips[1]
|
|
153
220
|
if not grip then
|
|
154
221
|
self:_clear()
|
|
155
222
|
return false
|
|
156
223
|
end
|
|
157
224
|
|
|
158
|
-
if not self:
|
|
225
|
+
if not self:_oldCalculatePoint(grip.attachment.WorldPosition) then
|
|
159
226
|
self:_clear()
|
|
160
227
|
return false
|
|
161
228
|
end
|
|
@@ -167,9 +234,50 @@ function ArmIKBase:_clear()
|
|
|
167
234
|
self._offset = nil
|
|
168
235
|
self._elbowTransform = nil
|
|
169
236
|
self._shoulderTransform = nil
|
|
237
|
+
self._wristTransform = nil
|
|
170
238
|
end
|
|
171
239
|
|
|
172
|
-
function ArmIKBase:
|
|
240
|
+
function ArmIKBase:_newUpdate()
|
|
241
|
+
local grip = self._grips[1]
|
|
242
|
+
if not (grip and self._resources:IsReady()) then
|
|
243
|
+
self._elbowTransform = nil
|
|
244
|
+
self._shoulderTransform = nil
|
|
245
|
+
self._wristTransform = nil
|
|
246
|
+
return false
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
local targetCFrame = grip.attachment.WorldCFrame
|
|
250
|
+
|
|
251
|
+
local upperTorsoShoulderRigAttachment = self._resources:Get("UpperTorsoShoulderRigAttachment")
|
|
252
|
+
|
|
253
|
+
local upperArmShoulderRigAttachment = self._resources:Get("UpperArmShoulderRigAttachment")
|
|
254
|
+
local upperArmElbowRigAttachment = self._resources:Get("UpperArmElbowRigAttachment")
|
|
255
|
+
local elbowOffset = upperArmElbowRigAttachment.Position - upperArmShoulderRigAttachment.Position
|
|
256
|
+
|
|
257
|
+
local lowerArmElbowRigAttachment = self._resources:Get("LowerArmElbowRigAttachment")
|
|
258
|
+
local lowerArmWristRigAttachment = self._resources:Get("LowerArmWristRigAttachment")
|
|
259
|
+
local wristOffset = lowerArmWristRigAttachment.Position - lowerArmElbowRigAttachment.Position
|
|
260
|
+
|
|
261
|
+
local handWristRigAttachment = self._resources:Get("HandWristRigAttachment")
|
|
262
|
+
local handGripAttachment = self._resources:Get("HandGripAttachment")
|
|
263
|
+
local handOffset = handGripAttachment.Position - handWristRigAttachment.Position
|
|
264
|
+
|
|
265
|
+
-- TODO: Cache config
|
|
266
|
+
local config = LimbIKUtils.createConfig(elbowOffset, wristOffset + handOffset, 1)
|
|
267
|
+
local relTargetCFrame = upperTorsoShoulderRigAttachment.WorldCFrame:toObjectSpace(targetCFrame)
|
|
268
|
+
|
|
269
|
+
-- TODO: Allow configuration
|
|
270
|
+
local ELBOW_ANGLE = math.rad(20)
|
|
271
|
+
local shoulderQFrame, elbowQFrame, wristQFrame = LimbIKUtils.solveLimb(config, QFrame.fromCFrameClosestTo(relTargetCFrame, QFrame.new()), self._direction*ELBOW_ANGLE)
|
|
272
|
+
|
|
273
|
+
self._shoulderTransform = QFrame.toCFrame(shoulderQFrame)
|
|
274
|
+
self._elbowTransform = QFrame.toCFrame(elbowQFrame)
|
|
275
|
+
self._wristTransform = QFrame.toCFrame(wristQFrame)
|
|
276
|
+
|
|
277
|
+
return true
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
function ArmIKBase:_oldCalculatePoint(targetPositionWorld)
|
|
173
281
|
if not self._resources:IsReady() then
|
|
174
282
|
return false
|
|
175
283
|
end
|
|
@@ -182,9 +290,9 @@ function ArmIKBase:_calculatePoint(targetPositionWorld)
|
|
|
182
290
|
return false
|
|
183
291
|
end
|
|
184
292
|
|
|
185
|
-
local base = shoulder.Part0.CFrame * shoulder.C0
|
|
186
|
-
local elbowCFrame = elbow.Part0.CFrame * elbow.C0
|
|
187
|
-
local wristCFrame = elbow.Part1.CFrame * wrist.C0
|
|
293
|
+
local base = shoulder.Part0.CFrame * (self._testDefaultShoulderC0 or shoulder.C0)
|
|
294
|
+
local elbowCFrame = elbow.Part0.CFrame * (self._testDefaultElbowC0 or elbow.C0)
|
|
295
|
+
local wristCFrame = elbow.Part1.CFrame * (self._testDefaultWristC0 or wrist.C0)
|
|
188
296
|
|
|
189
297
|
local r0 = (base.Position - elbowCFrame.Position).Magnitude
|
|
190
298
|
local r1 = (elbowCFrame.Position - wristCFrame.Position).Magnitude
|
|
@@ -216,7 +324,6 @@ function ArmIKBase:_calculatePoint(targetPositionWorld)
|
|
|
216
324
|
|
|
217
325
|
self._shoulderXAngle = -baseAngle
|
|
218
326
|
self._elbowXAngle = -elbowAngle
|
|
219
|
-
|
|
220
327
|
self._offset = offset.unit * d
|
|
221
328
|
|
|
222
329
|
return true
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
--[[
|
|
2
|
+
@class ArmIKBase.story
|
|
3
|
+
]]
|
|
4
|
+
|
|
5
|
+
local require = require(game:GetService("ServerScriptService"):FindFirstChild("LoaderUtils", true).Parent).load(script)
|
|
6
|
+
|
|
7
|
+
local Workspace = game:GetService("Workspace")
|
|
8
|
+
local RunService = game:GetService("RunService")
|
|
9
|
+
|
|
10
|
+
local Maid = require("Maid")
|
|
11
|
+
local RigBuilderUtils = require("RigBuilderUtils")
|
|
12
|
+
local ArmIKBase = require("ArmIKBase")
|
|
13
|
+
|
|
14
|
+
return function(_target)
|
|
15
|
+
local maid = Maid.new()
|
|
16
|
+
|
|
17
|
+
maid:GivePromise(RigBuilderUtils.promisePlayerRig(4397833)):Then(function(character)
|
|
18
|
+
maid:GiveTask(character)
|
|
19
|
+
|
|
20
|
+
local humanoid = character.Humanoid
|
|
21
|
+
local position = Workspace.CurrentCamera.CFrame:pointToWorldSpace(Vector3.new(0, 0, -10))
|
|
22
|
+
|
|
23
|
+
local armIKBase = ArmIKBase.new(humanoid, "Right")
|
|
24
|
+
maid:GiveTask(armIKBase)
|
|
25
|
+
|
|
26
|
+
local attachment = Instance.new("Attachment")
|
|
27
|
+
attachment.Name = "IKRigStoryTarget"
|
|
28
|
+
attachment.Parent = workspace.Terrain
|
|
29
|
+
attachment.WorldPosition = position + Workspace.CurrentCamera.CFrame:vectorToWorldSpace(Vector3.new(2, 0, 1))
|
|
30
|
+
maid:GiveTask(attachment)
|
|
31
|
+
|
|
32
|
+
armIKBase:Grip(attachment)
|
|
33
|
+
|
|
34
|
+
humanoid.RootPart.CFrame = CFrame.new(position)
|
|
35
|
+
character.Parent = workspace
|
|
36
|
+
humanoid.RootPart.CFrame = CFrame.new(position)
|
|
37
|
+
|
|
38
|
+
maid:GiveTask(RunService.RenderStepped:Connect(function()
|
|
39
|
+
armIKBase:Update()
|
|
40
|
+
end))
|
|
41
|
+
end)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
return function()
|
|
45
|
+
maid:DoCleaning()
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -69,6 +69,10 @@ function IKRigBase:GetTorso()
|
|
|
69
69
|
end
|
|
70
70
|
|
|
71
71
|
function IKRigBase:PromiseLeftArm()
|
|
72
|
+
if self._obj.RigType ~= Enum.HumanoidRigType.R15 then
|
|
73
|
+
return Promise.rejected("Rig is not HumanoidRigType.R15")
|
|
74
|
+
end
|
|
75
|
+
|
|
72
76
|
return Promise.resolved(self:GetLeftArm())
|
|
73
77
|
end
|
|
74
78
|
|
|
@@ -81,6 +85,10 @@ function IKRigBase:GetLeftArm()
|
|
|
81
85
|
end
|
|
82
86
|
|
|
83
87
|
function IKRigBase:PromiseRightArm()
|
|
88
|
+
if self._obj.RigType ~= Enum.HumanoidRigType.R15 then
|
|
89
|
+
return Promise.rejected("Rig is not HumanoidRigType.R15")
|
|
90
|
+
end
|
|
91
|
+
|
|
84
92
|
return Promise.resolved(self:GetRightArm())
|
|
85
93
|
end
|
|
86
94
|
|
|
@@ -96,7 +104,7 @@ function IKRigBase:_getNewArm(armName)
|
|
|
96
104
|
assert(armName == "Left" or armName == "Right", "Bad armName")
|
|
97
105
|
|
|
98
106
|
if self._obj.RigType ~= Enum.HumanoidRigType.R15 then
|
|
99
|
-
return
|
|
107
|
+
return nil
|
|
100
108
|
end
|
|
101
109
|
|
|
102
110
|
local newIk = ArmIKBase.new(self._obj, armName)
|
|
@@ -1,18 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "IKTest",
|
|
3
3
|
"tree": {
|
|
4
4
|
"$className": "DataModel",
|
|
5
|
-
"ReplicatedStorage": {
|
|
6
|
-
"Nevermore": {
|
|
7
|
-
"$path": "../node_modules/@quenty/loader"
|
|
8
|
-
}
|
|
9
|
-
},
|
|
10
5
|
"ServerScriptService": {
|
|
11
|
-
"
|
|
12
|
-
"$
|
|
13
|
-
"IK": {
|
|
14
|
-
"$path": ".."
|
|
15
|
-
}
|
|
6
|
+
"ik": {
|
|
7
|
+
"$path": ".."
|
|
16
8
|
},
|
|
17
9
|
"Script": {
|
|
18
10
|
"$path": "scripts/Server"
|
|
@@ -2,13 +2,13 @@
|
|
|
2
2
|
@class ClientMain
|
|
3
3
|
]]
|
|
4
4
|
|
|
5
|
-
local
|
|
5
|
+
local packages = game:GetService("ReplicatedStorage"):WaitForChild("Packages")
|
|
6
6
|
|
|
7
|
-
local serviceBag = require(
|
|
8
|
-
serviceBag:GetService(
|
|
7
|
+
local serviceBag = require(packages.ServiceBag).new()
|
|
8
|
+
local ikServiceClient = serviceBag:GetService(packages.IKServiceClient)
|
|
9
9
|
|
|
10
10
|
serviceBag:Init()
|
|
11
11
|
serviceBag:Start()
|
|
12
12
|
|
|
13
13
|
-- Configure
|
|
14
|
-
|
|
14
|
+
ikServiceClient:SetLookAround(true)
|
|
@@ -2,16 +2,22 @@
|
|
|
2
2
|
@class ServerMain
|
|
3
3
|
]]
|
|
4
4
|
|
|
5
|
-
local
|
|
5
|
+
local ServerScriptService = game:GetService("ServerScriptService")
|
|
6
|
+
local RunService = game:GetService("RunService")
|
|
6
7
|
|
|
7
|
-
local
|
|
8
|
-
|
|
8
|
+
local loader = ServerScriptService:FindFirstChild("LoaderUtils", true).Parent
|
|
9
|
+
local packages = require(loader).bootstrapGame(ServerScriptService.ik)
|
|
9
10
|
|
|
11
|
+
local serviceBag = require(packages.ServiceBag).new()
|
|
12
|
+
local ikService = serviceBag:GetService(packages.IKService)
|
|
13
|
+
|
|
14
|
+
-- Start game
|
|
10
15
|
serviceBag:Init()
|
|
11
16
|
serviceBag:Start()
|
|
12
17
|
|
|
18
|
+
|
|
13
19
|
-- Build test NPC rigs
|
|
14
|
-
local RigBuilderUtils = require(
|
|
20
|
+
local RigBuilderUtils = require(packages.RigBuilderUtils)
|
|
15
21
|
RigBuilderUtils.promiseR15MeshRig()
|
|
16
22
|
:Then(function(character)
|
|
17
23
|
local humanoid = character.Humanoid
|
|
@@ -21,6 +27,8 @@ RigBuilderUtils.promiseR15MeshRig()
|
|
|
21
27
|
character.Parent = workspace
|
|
22
28
|
humanoid.RootPart.CFrame = CFrame.new(0, 25, 0)
|
|
23
29
|
|
|
24
|
-
-- look
|
|
25
|
-
|
|
30
|
+
-- look at origin
|
|
31
|
+
RunService.Stepped:Connect(function()
|
|
32
|
+
ikService:UpdateServerRigTarget(humanoid, Vector3.new(0, 0, 0))
|
|
33
|
+
end)
|
|
26
34
|
end)
|