1use box2d_rust::body::create_body;
6use box2d_rust::collision::Capsule;
7use box2d_rust::debug_draw::HexColor;
8use box2d_rust::geometry::make_polygon;
9use box2d_rust::hull::compute_hull;
10use box2d_rust::id::{BodyId, JointId};
11use box2d_rust::math_functions::{make_rot, offset_pos, Pos, Vec2, PI};
12use box2d_rust::shape::{create_capsule_shape, create_polygon_shape};
13use box2d_rust::types::{default_body_def, default_shape_def, BodyType};
14use box2d_rust::world::World;
15
16use super::{
17 attach_revolute_joint, Human, BONE_HEAD, BONE_HIP, BONE_LOWER_LEFT_ARM, BONE_LOWER_LEFT_LEG,
18 BONE_LOWER_RIGHT_ARM, BONE_LOWER_RIGHT_LEG, BONE_TORSO, BONE_UPPER_LEFT_ARM,
19 BONE_UPPER_LEFT_LEG, BONE_UPPER_RIGHT_ARM, BONE_UPPER_RIGHT_LEG,
20};
21
22#[allow(clippy::too_many_arguments)]
24pub fn create_human(
25 human: &mut Human,
26 world: &mut World,
27 position: Pos,
28 scale: f32,
29 friction_torque: f32,
30 hertz: f32,
31 damping_ratio: f32,
32 group_index: i32,
33 user_data: u64,
34 colorize: bool,
35) {
36 debug_assert!(!human.is_spawned);
37
38 for bone in human.bones.iter_mut() {
39 bone.body_id = BodyId::default();
40 bone.joint_id = JointId::default();
41 bone.friction_scale = 1.0;
42 bone.parent_index = -1;
43 }
44
45 human.original_scale = scale;
46 human.scale = scale;
47 human.friction_torque = friction_torque;
48
49 let mut body_def = default_body_def();
50 body_def.type_ = BodyType::Dynamic;
51 body_def.sleep_threshold = 0.1;
52 body_def.user_data = user_data;
53
54 let mut shape_def = default_shape_def();
55 shape_def.material.friction = 0.2;
56 shape_def.filter.group_index = -group_index;
57 shape_def.filter.category_bits = 2;
58 shape_def.filter.mask_bits = 1 | 2;
59
60 let mut foot_shape_def = shape_def;
61 foot_shape_def.material.friction = 0.05;
62 foot_shape_def.filter.category_bits = 2;
64 foot_shape_def.filter.mask_bits = 1;
65
66 if colorize {
67 foot_shape_def.material.custom_color = HexColor::SADDLE_BROWN.0;
68 }
69
70 let s = scale;
71 let max_torque = friction_torque * s;
72 let enable_motor = true;
73 let enable_limit = true;
74 let draw_size = 0.05;
75
76 let shirt_color = HexColor::MEDIUM_TURQUOISE;
77 let pant_color = HexColor::DODGER_BLUE;
78
79 let skin_colors = [
80 HexColor::NAVAJO_WHITE,
81 HexColor::LIGHT_YELLOW,
82 HexColor::PERU,
83 HexColor::TAN,
84 ];
85 let skin_color = skin_colors[(group_index % 4) as usize];
86
87 {
89 human.bones[BONE_HIP].parent_index = -1;
90
91 body_def.position = offset_pos(
92 position,
93 Vec2 {
94 x: 0.0,
95 y: 0.95 * s,
96 },
97 );
98 body_def.linear_damping = 0.0;
99 body_def.name = "hip".to_string();
100
101 let body_id = create_body(world, &body_def);
102 human.bones[BONE_HIP].body_id = body_id;
103
104 if colorize {
105 shape_def.material.custom_color = pant_color.0;
106 }
107
108 let capsule = Capsule {
109 center1: Vec2 {
110 x: 0.0,
111 y: -0.02 * s,
112 },
113 center2: Vec2 {
114 x: 0.0,
115 y: 0.02 * s,
116 },
117 radius: 0.095 * s,
118 };
119 create_capsule_shape(world, body_id, &shape_def, &capsule);
120 }
121
122 {
124 human.bones[BONE_TORSO].parent_index = BONE_HIP as i32;
125
126 body_def.position = offset_pos(position, Vec2 { x: 0.0, y: 1.2 * s });
127 body_def.linear_damping = 0.0;
128 body_def.name = "torso".to_string();
129
130 let body_id = create_body(world, &body_def);
131 human.bones[BONE_TORSO].body_id = body_id;
132 human.bones[BONE_TORSO].friction_scale = 0.5;
133 body_def.type_ = BodyType::Dynamic;
134
135 if colorize {
136 shape_def.material.custom_color = shirt_color.0;
137 }
138
139 let capsule = Capsule {
140 center1: Vec2 {
141 x: 0.0,
142 y: -0.135 * s,
143 },
144 center2: Vec2 {
145 x: 0.0,
146 y: 0.135 * s,
147 },
148 radius: 0.09 * s,
149 };
150 create_capsule_shape(world, body_id, &shape_def, &capsule);
151
152 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 1.0 * s });
153 let parent = human.bones[BONE_HIP].body_id;
154 let joint_id = attach_revolute_joint(
155 world,
156 parent,
157 body_id,
158 pivot,
159 -0.25 * PI,
160 0.0,
161 enable_limit,
162 enable_motor,
163 human.bones[BONE_TORSO].friction_scale * max_torque,
164 hertz > 0.0,
165 hertz,
166 damping_ratio,
167 draw_size,
168 None,
169 );
170 human.bones[BONE_TORSO].joint_id = joint_id;
171 }
172
173 {
175 human.bones[BONE_HEAD].parent_index = BONE_TORSO as i32;
176
177 body_def.position = offset_pos(
178 position,
179 Vec2 {
180 x: 0.0 * s,
181 y: 1.475 * s,
182 },
183 );
184 body_def.linear_damping = 0.1;
185 body_def.name = "head".to_string();
186
187 let body_id = create_body(world, &body_def);
188 human.bones[BONE_HEAD].body_id = body_id;
189 human.bones[BONE_HEAD].friction_scale = 0.25;
190
191 if colorize {
192 shape_def.material.custom_color = skin_color.0;
193 }
194
195 let capsule = Capsule {
196 center1: Vec2 {
197 x: 0.0,
198 y: -0.038 * s,
199 },
200 center2: Vec2 {
201 x: 0.0,
202 y: 0.039 * s,
203 },
204 radius: 0.075 * s,
205 };
206 create_capsule_shape(world, body_id, &shape_def, &capsule);
207
208 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 1.4 * s });
209 let parent = human.bones[BONE_TORSO].body_id;
210 let joint_id = attach_revolute_joint(
211 world,
212 parent,
213 body_id,
214 pivot,
215 -0.3 * PI,
216 0.1 * PI,
217 enable_limit,
218 enable_motor,
219 human.bones[BONE_HEAD].friction_scale * max_torque,
220 hertz > 0.0,
221 hertz,
222 damping_ratio,
223 draw_size,
224 None,
225 );
226 human.bones[BONE_HEAD].joint_id = joint_id;
227 }
228
229 {
231 human.bones[BONE_UPPER_LEFT_LEG].parent_index = BONE_HIP as i32;
232
233 body_def.position = offset_pos(
234 position,
235 Vec2 {
236 x: 0.0,
237 y: 0.775 * s,
238 },
239 );
240 body_def.linear_damping = 0.0;
241 body_def.name = "upper_left_leg".to_string();
242
243 let body_id = create_body(world, &body_def);
244 human.bones[BONE_UPPER_LEFT_LEG].body_id = body_id;
245 human.bones[BONE_UPPER_LEFT_LEG].friction_scale = 1.0;
246
247 if colorize {
248 shape_def.material.custom_color = pant_color.0;
249 }
250
251 let capsule = Capsule {
252 center1: Vec2 {
253 x: 0.0,
254 y: -0.125 * s,
255 },
256 center2: Vec2 {
257 x: 0.0,
258 y: 0.125 * s,
259 },
260 radius: 0.06 * s,
261 };
262 create_capsule_shape(world, body_id, &shape_def, &capsule);
263
264 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 0.9 * s });
265 let parent = human.bones[BONE_HIP].body_id;
266 let joint_id = attach_revolute_joint(
267 world,
268 parent,
269 body_id,
270 pivot,
271 -0.05 * PI,
272 0.4 * PI,
273 enable_limit,
274 enable_motor,
275 human.bones[BONE_UPPER_LEFT_LEG].friction_scale * max_torque,
276 hertz > 0.0,
277 hertz,
278 damping_ratio,
279 draw_size,
280 None,
281 );
282 human.bones[BONE_UPPER_LEFT_LEG].joint_id = joint_id;
283 }
284
285 let foot_points = [
286 Vec2 {
287 x: -0.03 * s,
288 y: -0.185 * s,
289 },
290 Vec2 {
291 x: 0.11 * s,
292 y: -0.185 * s,
293 },
294 Vec2 {
295 x: 0.11 * s,
296 y: -0.16 * s,
297 },
298 Vec2 {
299 x: -0.03 * s,
300 y: -0.14 * s,
301 },
302 ];
303 let foot_hull = compute_hull(&foot_points);
304 let foot_polygon = make_polygon(&foot_hull, 0.015 * s);
305
306 {
308 human.bones[BONE_LOWER_LEFT_LEG].parent_index = BONE_UPPER_LEFT_LEG as i32;
309
310 body_def.position = offset_pos(
311 position,
312 Vec2 {
313 x: 0.0,
314 y: 0.475 * s,
315 },
316 );
317 body_def.linear_damping = 0.0;
318 body_def.name = "lower_left_leg".to_string();
319
320 let body_id = create_body(world, &body_def);
321 human.bones[BONE_LOWER_LEFT_LEG].body_id = body_id;
322 human.bones[BONE_LOWER_LEFT_LEG].friction_scale = 0.5;
323
324 if colorize {
325 shape_def.material.custom_color = pant_color.0;
326 }
327
328 let capsule = Capsule {
329 center1: Vec2 {
330 x: 0.0,
331 y: -0.155 * s,
332 },
333 center2: Vec2 {
334 x: 0.0,
335 y: 0.125 * s,
336 },
337 radius: 0.045 * s,
338 };
339 create_capsule_shape(world, body_id, &shape_def, &capsule);
340
341 create_polygon_shape(world, body_id, &foot_shape_def, &foot_polygon);
342
343 let pivot = offset_pos(
344 position,
345 Vec2 {
346 x: 0.0,
347 y: 0.625 * s,
348 },
349 );
350 let parent = human.bones[BONE_UPPER_LEFT_LEG].body_id;
351 let joint_id = attach_revolute_joint(
352 world,
353 parent,
354 body_id,
355 pivot,
356 -0.5 * PI,
357 -0.02 * PI,
358 enable_limit,
359 enable_motor,
360 human.bones[BONE_LOWER_LEFT_LEG].friction_scale * max_torque,
361 hertz > 0.0,
362 hertz,
363 damping_ratio,
364 draw_size,
365 None,
366 );
367 human.bones[BONE_LOWER_LEFT_LEG].joint_id = joint_id;
368 }
369
370 {
372 human.bones[BONE_UPPER_RIGHT_LEG].parent_index = BONE_HIP as i32;
373
374 body_def.position = offset_pos(
375 position,
376 Vec2 {
377 x: 0.0,
378 y: 0.775 * s,
379 },
380 );
381 body_def.linear_damping = 0.0;
382 body_def.name = "upper_right_leg".to_string();
383
384 let body_id = create_body(world, &body_def);
385 human.bones[BONE_UPPER_RIGHT_LEG].body_id = body_id;
386 human.bones[BONE_UPPER_RIGHT_LEG].friction_scale = 1.0;
387
388 if colorize {
389 shape_def.material.custom_color = pant_color.0;
390 }
391
392 let capsule = Capsule {
393 center1: Vec2 {
394 x: 0.0,
395 y: -0.125 * s,
396 },
397 center2: Vec2 {
398 x: 0.0,
399 y: 0.125 * s,
400 },
401 radius: 0.06 * s,
402 };
403 create_capsule_shape(world, body_id, &shape_def, &capsule);
404
405 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 0.9 * s });
406 let parent = human.bones[BONE_HIP].body_id;
407 let joint_id = attach_revolute_joint(
408 world,
409 parent,
410 body_id,
411 pivot,
412 -0.05 * PI,
413 0.4 * PI,
414 enable_limit,
415 enable_motor,
416 human.bones[BONE_UPPER_RIGHT_LEG].friction_scale * max_torque,
417 hertz > 0.0,
418 hertz,
419 damping_ratio,
420 draw_size,
421 None,
422 );
423 human.bones[BONE_UPPER_RIGHT_LEG].joint_id = joint_id;
424 }
425
426 {
428 human.bones[BONE_LOWER_RIGHT_LEG].parent_index = BONE_UPPER_RIGHT_LEG as i32;
429
430 body_def.position = offset_pos(
431 position,
432 Vec2 {
433 x: 0.0,
434 y: 0.475 * s,
435 },
436 );
437 body_def.linear_damping = 0.0;
438 body_def.name = "lower_right_leg".to_string();
439
440 let body_id = create_body(world, &body_def);
441 human.bones[BONE_LOWER_RIGHT_LEG].body_id = body_id;
442 human.bones[BONE_LOWER_RIGHT_LEG].friction_scale = 0.5;
443
444 if colorize {
445 shape_def.material.custom_color = pant_color.0;
446 }
447
448 let capsule = Capsule {
449 center1: Vec2 {
450 x: 0.0,
451 y: -0.155 * s,
452 },
453 center2: Vec2 {
454 x: 0.0,
455 y: 0.125 * s,
456 },
457 radius: 0.045 * s,
458 };
459 create_capsule_shape(world, body_id, &shape_def, &capsule);
460
461 create_polygon_shape(world, body_id, &foot_shape_def, &foot_polygon);
462
463 let pivot = offset_pos(
464 position,
465 Vec2 {
466 x: 0.0,
467 y: 0.625 * s,
468 },
469 );
470 let parent = human.bones[BONE_UPPER_RIGHT_LEG].body_id;
471 let joint_id = attach_revolute_joint(
472 world,
473 parent,
474 body_id,
475 pivot,
476 -0.5 * PI,
477 -0.02 * PI,
478 enable_limit,
479 enable_motor,
480 human.bones[BONE_LOWER_RIGHT_LEG].friction_scale * max_torque,
481 hertz > 0.0,
482 hertz,
483 damping_ratio,
484 draw_size,
485 None,
486 );
487 human.bones[BONE_LOWER_RIGHT_LEG].joint_id = joint_id;
488 }
489
490 {
492 human.bones[BONE_UPPER_LEFT_ARM].parent_index = BONE_TORSO as i32;
493 human.bones[BONE_UPPER_LEFT_ARM].friction_scale = 0.5;
494
495 body_def.position = offset_pos(
496 position,
497 Vec2 {
498 x: 0.0,
499 y: 1.225 * s,
500 },
501 );
502 body_def.linear_damping = 0.0;
503 body_def.name = "upper_left_arm".to_string();
504
505 let body_id = create_body(world, &body_def);
506 human.bones[BONE_UPPER_LEFT_ARM].body_id = body_id;
507
508 if colorize {
509 shape_def.material.custom_color = shirt_color.0;
510 }
511
512 let capsule = Capsule {
513 center1: Vec2 {
514 x: 0.0,
515 y: -0.125 * s,
516 },
517 center2: Vec2 {
518 x: 0.0,
519 y: 0.125 * s,
520 },
521 radius: 0.035 * s,
522 };
523 create_capsule_shape(world, body_id, &shape_def, &capsule);
524
525 let pivot = offset_pos(
526 position,
527 Vec2 {
528 x: 0.0,
529 y: 1.35 * s,
530 },
531 );
532 let parent = human.bones[BONE_TORSO].body_id;
533 let joint_id = attach_revolute_joint(
534 world,
535 parent,
536 body_id,
537 pivot,
538 -0.1 * PI,
539 0.8 * PI,
540 enable_limit,
541 enable_motor,
542 human.bones[BONE_UPPER_LEFT_ARM].friction_scale * max_torque,
543 hertz > 0.0,
544 hertz,
545 damping_ratio,
546 draw_size,
547 None,
548 );
549 human.bones[BONE_UPPER_LEFT_ARM].joint_id = joint_id;
550 }
551
552 {
554 human.bones[BONE_LOWER_LEFT_ARM].parent_index = BONE_UPPER_LEFT_ARM as i32;
555
556 body_def.position = offset_pos(
557 position,
558 Vec2 {
559 x: 0.0,
560 y: 0.975 * s,
561 },
562 );
563 body_def.linear_damping = 0.1;
564 body_def.name = "lower_left_arm".to_string();
565
566 let body_id = create_body(world, &body_def);
567 human.bones[BONE_LOWER_LEFT_ARM].body_id = body_id;
568 human.bones[BONE_LOWER_LEFT_ARM].friction_scale = 0.1;
569
570 if colorize {
571 shape_def.material.custom_color = skin_color.0;
572 }
573
574 let capsule = Capsule {
575 center1: Vec2 {
576 x: 0.0,
577 y: -0.125 * s,
578 },
579 center2: Vec2 {
580 x: 0.0,
581 y: 0.125 * s,
582 },
583 radius: 0.03 * s,
584 };
585 create_capsule_shape(world, body_id, &shape_def, &capsule);
586
587 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 1.1 * s });
588 let parent = human.bones[BONE_UPPER_LEFT_ARM].body_id;
589 let joint_id = attach_revolute_joint(
590 world,
591 parent,
592 body_id,
593 pivot,
594 -0.2 * PI,
595 0.3 * PI,
596 enable_limit,
597 enable_motor,
598 human.bones[BONE_LOWER_LEFT_ARM].friction_scale * max_torque,
599 hertz > 0.0,
600 hertz,
601 damping_ratio,
602 draw_size,
603 Some(make_rot(0.25 * PI)),
604 );
605 human.bones[BONE_LOWER_LEFT_ARM].joint_id = joint_id;
606 }
607
608 {
610 human.bones[BONE_UPPER_RIGHT_ARM].parent_index = BONE_TORSO as i32;
611
612 body_def.position = offset_pos(
613 position,
614 Vec2 {
615 x: 0.0,
616 y: 1.225 * s,
617 },
618 );
619 body_def.linear_damping = 0.0;
620 body_def.name = "upper_right_arm".to_string();
621
622 let body_id = create_body(world, &body_def);
623 human.bones[BONE_UPPER_RIGHT_ARM].body_id = body_id;
624 human.bones[BONE_UPPER_RIGHT_ARM].friction_scale = 0.5;
625
626 if colorize {
627 shape_def.material.custom_color = shirt_color.0;
628 }
629
630 let capsule = Capsule {
631 center1: Vec2 {
632 x: 0.0,
633 y: -0.125 * s,
634 },
635 center2: Vec2 {
636 x: 0.0,
637 y: 0.125 * s,
638 },
639 radius: 0.035 * s,
640 };
641 create_capsule_shape(world, body_id, &shape_def, &capsule);
642
643 let pivot = offset_pos(
644 position,
645 Vec2 {
646 x: 0.0,
647 y: 1.35 * s,
648 },
649 );
650 let parent = human.bones[BONE_TORSO].body_id;
651 let joint_id = attach_revolute_joint(
652 world,
653 parent,
654 body_id,
655 pivot,
656 -0.1 * PI,
657 0.8 * PI,
658 enable_limit,
659 enable_motor,
660 human.bones[BONE_UPPER_RIGHT_ARM].friction_scale * max_torque,
661 hertz > 0.0,
662 hertz,
663 damping_ratio,
664 draw_size,
665 None,
666 );
667 human.bones[BONE_UPPER_RIGHT_ARM].joint_id = joint_id;
668 }
669
670 {
672 human.bones[BONE_LOWER_RIGHT_ARM].parent_index = BONE_UPPER_RIGHT_ARM as i32;
673
674 body_def.position = offset_pos(
675 position,
676 Vec2 {
677 x: 0.0,
678 y: 0.975 * s,
679 },
680 );
681 body_def.linear_damping = 0.1;
682 body_def.name = "lower_right_arm".to_string();
683
684 let body_id = create_body(world, &body_def);
685 human.bones[BONE_LOWER_RIGHT_ARM].body_id = body_id;
686 human.bones[BONE_LOWER_RIGHT_ARM].friction_scale = 0.1;
687
688 if colorize {
689 shape_def.material.custom_color = skin_color.0;
690 }
691
692 let capsule = Capsule {
693 center1: Vec2 {
694 x: 0.0,
695 y: -0.125 * s,
696 },
697 center2: Vec2 {
698 x: 0.0,
699 y: 0.125 * s,
700 },
701 radius: 0.03 * s,
702 };
703 create_capsule_shape(world, body_id, &shape_def, &capsule);
704
705 let pivot = offset_pos(position, Vec2 { x: 0.0, y: 1.1 * s });
706 let parent = human.bones[BONE_UPPER_RIGHT_ARM].body_id;
707 let joint_id = attach_revolute_joint(
708 world,
709 parent,
710 body_id,
711 pivot,
712 -0.2 * PI,
713 0.3 * PI,
714 enable_limit,
715 enable_motor,
716 human.bones[BONE_LOWER_RIGHT_ARM].friction_scale * max_torque,
717 hertz > 0.0,
718 hertz,
719 damping_ratio,
720 draw_size,
721 Some(make_rot(0.25 * PI)),
722 );
723 human.bones[BONE_LOWER_RIGHT_ARM].joint_id = joint_id;
724 }
725
726 human.is_spawned = true;
727}