-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathprocedural_walking_spider.fcs
222 lines (174 loc) · 6.22 KB
/
procedural_walking_spider.fcs
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
on Play
{
const global float SEGMENTS_PER_LEG = 3
const global float POINTS_PER_LEG = SEGMENTS_PER_LEG + 1
const global float NUMB_LEGS = 4
const global float TOTAL_POINTS = POINTS_PER_LEG * NUMB_LEGS
const global float BODY_HEIGHT = 1.6
// dist when not moving
const global float RELOCATE_LIMB_DIST_BASE = .3
// dist when moving at max speed + RELOCATE_LIMB_DIST_BASE
const global float RELOCATE_LIMB_DIST = .7
const global float MOVE_SPEED = 0.075
const global float LIMB_INTERPOLATION_SPEED = 0.2
const global float LIMB_INTERPOLATION_SPEED_INV = 1 - LIMB_INTERPOLATION_SPEED
const global float BODY_INTERPOLATION_SPEED = 0.15
const global float BODY_INTERPOLATION_SPEED_INV = 1 - BODY_INTERPOLATION_SPEED
const global float CAN_MOVE_AFTER = 15
const global float CAN_MOVE_AFTER_ADJACENT = 10 // !!! MUST BE SMALLER THAN CAN_MOVE_AFTER !!!
#highlight
global obj body = getBlockById(BLOCK_STONE_BLOCK)
obj segmentPrefab = null // rod on the z axis, without collision
#endhighlight
global vec3 bodyPos = vec3(0, BODY_HEIGHT, 0)
const float legOff = 0.32
global array<vec3> legOffs =
[
vec3(legOff, 0, legOff),
vec3(legOff, 0, -legOff),
vec3(-legOff, 0, -legOff),
vec3(-legOff, 0, legOff)
]
global array<vec3> legDirs =
[
normalize(vec3( 1, 0, 1)),
normalize(vec3( 1, 0, -1)),
normalize(vec3(-1, 0, -1)),
normalize(vec3(-1, 0, 1))
]
global array<obj> legSegments
global array<float> legMoveStart
global array<float> lengths
global array<vec3> points
global array<vec3> targetPoints
global array<vec3> legCastHits
global array<vec3> legTargets
global float currentSpeed
// create segment objects
on Loop(null, NUMB_LEGS, out inline float li)
{
inline float sOff = li * SEGMENTS_PER_LEG
inline float pOff = li * POINTS_PER_LEG
on Loop(null, SEGMENTS_PER_LEG, out inline float _i)
{
inline float i = sOff + _i
segmentPrefab.clone(out inline obj segment)
legSegments.set(i, segment)
lengths.set(_i + pOff, 1)
}
}
}
// move
joystick(out vec3 joyDir, JOYSTICK_TYPE_XZ)
joyDir *= MOVE_SPEED
bodyPos += joyDir
currentSpeed = dist(null, joyDir)
inspect(currentSpeed)
updateLegs()
// body y pos
float bodyY = 0
on Loop(null, NUMB_LEGS, out inline float i)
{
bodyY += legCastHits.get(i).y
}
bodyY /= NUMB_LEGS
bodyY += BODY_HEIGHT
bodyPos.y = bodyY * BODY_INTERPOLATION_SPEED + bodyPos.y * BODY_INTERPOLATION_SPEED_INV
func updateLegs()
{
inline float currentFrame = getCurrentFrame()
on Loop(0, NUMB_LEGS, out inline float i)
{
vec3 rayPos = bodyPos + legDirs.get(i) * 1.5
raycast(rayPos + vec3(0, 2, 0), rayPos - vec3(0, 10, 0), out _, out vec3 hitPos, out _)
legCastHits.set(i, hitPos)
inline vec3 currentTarget = legTargets.get(i)
if (dist(hitPos, currentTarget) >= RELOCATE_LIMB_DIST_BASE + (currentSpeed / MOVE_SPEED) * RELOCATE_LIMB_DIST && checkCanMove(i))
{
setPtrValue(currentTarget, hitPos)
legMoveStart.set(i, currentFrame)
}
fabric(i, currentTarget)
}
body.setPos(bodyPos)
if (currentFrame == 0)
{
// set points to targetPoints
on Loop(null, TOTAL_POINTS, out inline float i)
{
points.set(i, targetPoints.get(i))
}
}
else
{
// interpolate points to targetPoints
on Loop(null, TOTAL_POINTS, out inline float i)
{
points.set(i, targetPoints.get(i) * LIMB_INTERPOLATION_SPEED + points.get(i) * LIMB_INTERPOLATION_SPEED_INV)
}
}
// set segment object positions
on Loop(null, NUMB_LEGS, out inline float li)
{
inline float sOff = li * SEGMENTS_PER_LEG
inline float pOff = li * POINTS_PER_LEG
on Loop(null, SEGMENTS_PER_LEG, out inline float _i)
{
inline float i = _i + pOff
inline float nextI = i + 1
inline vec3 point = points.get(i)
inline vec3 nextPoint = points.get(nextI)
legSegments.get(_i + sOff).setPos((point + nextPoint) / 2, lookRotation(nextPoint - point, vec3(0, 1, 0)))
}
}
}
// based on https://youtu.be/Hc9x1e85L0w?si=SR8pjkoIZcdPxRKN
func fabric(float limb, vec3 target)
{
inline float off = limb * POINTS_PER_LEG
// set first point
targetPoints.set(off, bodyPos + legOffs.get(limb))
// "lock" rotation to only 1 axis
on Loop(1, SEGMENTS_PER_LEG, out inline float _i)
{
inline float i = _i + off
inline float prevIndex = i - 1
targetPoints.set(i, targetPoints.get(prevIndex) + vec3(0, 1, 0) * lengths.get(prevIndex))
}
// 10 iterations
on Loop(0, 10, out _)
{
// set last point to target
targetPoints.set(off + SEGMENTS_PER_LEG, target)
// loop backwards
on Loop(POINTS_PER_LEG - 2, -1, out inline float _i)
{
inline float i = _i + off
inline float nextIndex = i + 1
inline vec3 point = targetPoints.get(i)
inline vec3 nextPoint = targetPoints.get(nextIndex)
vec3 move = normalize(point - nextPoint) * lengths.get(i)
targetPoints.set(i, nextPoint + move)
}
// set first point
targetPoints.set(off, bodyPos + legOffs.get(limb))
// loop forwards
on Loop(0, SEGMENTS_PER_LEG, out inline float _i)
{
inline float i = _i + off
inline float nextIndex = i + 1
inline vec3 point = targetPoints.get(i)
inline vec3 nextPoint = targetPoints.get(nextIndex)
inline vec3 move = normalize(nextPoint - point) * lengths.get(i)
targetPoints.set(nextIndex, point + move)
}
}
}
inline func bool checkCanMove(float leg)
{
inline float currentFrame = getCurrentFrame()
inline float canMoveTime = currentFrame - CAN_MOVE_AFTER_ADJACENT
return legMoveStart.get((leg + 1) % NUMB_LEGS) < canMoveTime &&
legMoveStart.get(((leg - 1) % NUMB_LEGS + NUMB_LEGS) % NUMB_LEGS) < canMoveTime &&
legMoveStart.get(leg) < currentFrame - CAN_MOVE_AFTER
}