Bodies Overview
JoltBody je bezpečný high-level GML zástupce jednoho rigid body ve výchozím Jolt worldu.
Tato stránka shrnuje společný lifecycle, motion typy, options, vlastnosti, kolize, raycasty a ověřené limity všech tvarů v sekci Bodies.
JoltBody#
JoltBody obsahuje generační native handle, world handle, typ shape, motion type, metadata rozměrů, GML user_data, volitelného vlastníka GameMaker instance a kolizní události posledního aktualizovaného framu. Není to C++ pointer. Handle kóduje slot a generaci; po zničení se generace změní a zastaralý handle je odmítnut. Hodnota 0 je neplatná. V běžném kódu používejte JoltBody, nikoli číslo z body.get_native_handle().
Motion typy#
| Motion type | Konstanta | Chování |
|---|---|---|
| Dynamic | JOLT_MOTION_DYNAMIC | Simulované těleso reagující na gravitaci, kontakty, síly, impulzy a constraints. Vytváří se funkcemi s příponou _create_dynamic. |
| Static | JOLT_MOTION_STATIC | Nepohyblivá kolizní geometrie pro podlahy, stěny, level mesh a terrain; neintegruje velocity a není určena pro síly. |
| Kinematic | JOLT_MOTION_KINEMATIC | Těleso řízené aplikací pomocí move_kinematic nebo move_kinematic_euler; může fyzicky ovlivňovat Dynamic body. |
Motion type lze číst body.get_motion_type() a měnit body.set_motion_type(type). Mesh, HeightField a Plane podporují v high-level API pouze Static.
Souřadnice a jednotky#
- API je pravotočivé a Z-up: X vlevo/vpravo, Y dopředu/dozadu, Z nahoru/dolů.
- Native převod rigid-body souřadnic je identitní.
- Doporučená konvence je 1 jednotka = 1 metr; wrapper žádnou fyzikální jednotku nevynucuje.
- High-level Euler úhly jsou ve stupních; quaternion má tvar {x, y, z, w}.
- High-level primitiva přijímají celé rozměry, low-level API výslovně half extents nebo half height.
Lifecycle#
jolt_start();
var body = jolt_box_create_dynamic(0, 0, 5, 1, 1, 1);
// Step event
jolt_update();
// Clean Up event
body.destroy();
jolt_stop();jolt_start(options) vytvoří výchozí world a lze jej volat opakovaně. jolt_update(frame_seconds) používá fixed timestep, standardně 1/60 s, provede simulaci a zpřístupní kontakty. jolt_stop() je idempotentní a odstraní spravované bodies, constraints, shape resources, compound buildery i world.
body.destroy() vrací true i při opakovaném volání. Poté body.is_valid() vrací false, GML handle se vynuluje, stale native handle je odmítnut a související high-level constraints jsou zneplatněny.
Společný options struct#
| Položka | Výchozí hodnota | Popis |
|---|---|---|
| rotation | {0,0,0,1} | Quaternion {x,y,z,w}; konečný a nenulový, Native jej normalizuje. |
| rotation_euler | {0,0,0} | Euler úhly ve stupních. Je-li zadána i rotation, rotation_euler se aplikuje později; doporučeno je zadat pouze jednu. |
| velocity | {0,0,0} | Počáteční world-space lineární rychlost; není povolena pro Static. |
| angular_velocity | {0,0,0} | Počáteční úhlová rychlost v radiánech za sekundu; není povolena pro Static. |
| friction | 0.2 | Konečné číslo >= 0; uvedený default platí pro Jolt 5.6.0. |
| restitution | 0.0 | Konečné číslo v rozsahu 0..1. |
| gravity_factor | 1.0 | Konečný násobek world gravity; vyžaduje motion properties. |
| linear_damping | 0.05 | Konečné číslo >= 0; vyžaduje motion properties. |
| angular_damping | 0.05 | Konečné číslo >= 0; vyžaduje motion properties. |
| mass | Jolt mass properties | Konečné číslo > 0, pouze Dynamic. |
| allow_sleeping | true | Boolean; vyžaduje motion properties. |
| layer | jolt_default_layer() | Platný JoltLayer ze stejného worldu. |
| sensor | false | Boolean určující trigger/sensor režim. |
| impact_sensor | false | Boolean nebo {min_value:real >= 0}; ukládá poslední relevantní impact, min_value je impulse v N·s. |
| ccd | false | Boolean; true zapne Jolt LinearCast CCD pro Dynamic rigid body. |
| motion_quality | Discrete | Advanced konstanta Discrete nebo LinearCast; má před ccd přednost. |
| center_of_mass_offset | {0,0,0} | Konečný lokální offset {x,y,z} mezi body originem a těžištěm. |
Chyby a návratové hodnoty#
if (is_undefined(body)) {
var error = jolt_get_error();
show_debug_message(error.context + ": " + error.message);
}jolt_get_error() vrací {code, message, context}. K dispozici jsou také jolt_has_error(), jolt_get_error_message(), jolt_clear_error(), a pro low-level/native stav jolt_get_last_error_code() a jolt_get_last_error_message().
JoltBody metody#
Lifecycle a identita#
body.is_valid()
body.get_native_handle()
body.get_world_handle()
body.destroy()Transformace a pohyb#
body.get_position()
body.set_position(x, y, z)
body.get_rotation()
body.get_rotation_euler()
body.set_rotation(x, y, z)
body.set_rotation(x, y, z, w)
body.set_rotation_euler(x, y, z)
body.get_transform()
body.get_velocity() / body.set_velocity(x, y, z)
body.get_angular_velocity() / body.set_angular_velocity(x, y, z)
body.move_kinematic(...)
body.move_kinematic_euler(...)Síly a impulzy — pouze Dynamic#
body.add_force(x, y, z)
body.add_force_at_position(fx, fy, fz, px, py, pz)
body.add_force_local(fx, fy, fz, local_x, local_y, local_z)
body.add_impulse(x, y, z)
body.add_impulse_at_position(ix, iy, iz, px, py, pz)
body.add_impulse_local(ix, iy, iz, local_x, local_y, local_z)
body.add_torque(x, y, z)
body.add_angular_impulse(x, y, z)Varianty at_position používají world-space bod.
Vlastnosti a aktivace#
body.set_friction(v) / body.get_friction()
body.set_restitution(v) / body.get_restitution()
body.set_gravity_factor(v) / body.get_gravity_factor()
body.set_linear_damping(v) / body.get_linear_damping()
body.set_angular_damping(v) / body.get_angular_damping()
body.set_mass(v) / body.get_mass()
body.activate() / body.deactivate() / body.is_active()
body.set_allow_sleeping(v) / body.get_allow_sleeping()
body.set_ccd(enabled) / body.get_ccd()
body.set_motion_quality(quality) / body.get_motion_quality()Impact Sensor#
var box = jolt_box_create_dynamic(0, 0, 5, 1, 1, 1, {
impact_sensor: {min_value: 10.0}
});
var impact = box.get_impact_sensor();
box.set_impact_sensor(true, 10.0);Impact Sensor je per-body opt-in snapshot posledního relevantního OnContactAdded nárazu. value a impulse jsou součet odhadovaných normálových contact impulses z Jolt EstimateCollisionResponse v N·s. Persistentní sequence umožňuje zpracovat každý nový impact právě jednou. Resting a sliding OnContactPersisted kontakty snapshot nepřepisují.
Výsledek obsahuje hit, value, impulse, normal_speed, position, normal, other_handle, živé other_body/other_user_data nebo undefined a sequence. Před prvním impactem je hit=false, sequence=0 a numerické hodnoty jsou nulové. Pokud vznikne více impactů v jednom native fyzikálním kroku, uloží se nejsilnější. Jedno jolt_update() může obsahovat několik kroků. Úplné chování a příklad jednorázové reakce najdete v Kolizní systém → Impact Sensor.
Continuous Collision Detection (CCD)#
Výchozí Discrete režim kontroluje kontakty v jednotlivých physics krocích, takže malé rychlé body může přeskočit tenkou překážku. LinearCast používá nativní Jolt shape cast podél lineárního pohybu automaticky během jolt_update().
var bullet = jolt_sphere_create_dynamic(0, 0, 1, 0.05, {
mass: 0.02,
ccd: true
});
bullet.set_velocity(0, 100, 0);
bullet.set_ccd(false); // Discrete
bullet.set_ccd(true); // LinearCastKonstanty jsou JOLT_MOTION_QUALITY_DISCRETE a JOLT_MOTION_QUALITY_LINEAR_CAST. Runtime změna zachová activation, sleeping permission a obě rychlosti. Wrapper CCD povoluje pouze Dynamic non-sensor rigid body s kladným inner radius; současné Box, Sphere, Capsule, Cylinder, Tapered Capsule, Tapered Cylinder, Convex a Compound jsou kompatibilní.
CCD není jolt_raycast(), jolt_raycast_all() ani Shape Query. Uživatel nevolá ruční cast; jde o solver vlastnost JoltBody.
Těžiště#
body.get_center_of_mass_position()
body.get_center_of_mass_offset()center_of_mass_offset se volí při vytvoření a později jej nelze změnit. První metoda vrací aktuální world-space pozici těžiště, druhá lokální offset uložený high-level wrapperem. Hodí se, když se má vizuální pivot a bod vyvážení tělesa lišit.
Collision layers#
jolt_default_layer() vrací výchozí layer. jolt_layer_create(name) vytvoří další JoltLayer; world podporuje nejvýše 32 uživatelských vrstev včetně Default. jolt_layer_set_collision(layer_a, layer_b, enabled) symetricky nastaví kolizi dvojice a nové vrstvy spolu standardně kolidují.
var trigger_layer = jolt_layer_create("Triggers");
jolt_layer_set_collision(trigger_layer, jolt_default_layer(), true);
var body = jolt_box_create_dynamic(0, 0, 3, 1, 1, 1, {layer: trigger_layer});Layer lze zadat v options nebo později přes body.set_layer(). body.get_layer() vrací JoltLayer, případně undefined při chybě nebo neznámém handle.
Sensors#
Každý rigid shape lze označit {sensor:true} nebo body.set_sensor(true); body.is_sensor() stav čte. Sensor vytváří kontaktní callbacky bez fyzické collision response, funguje tedy jako trigger volume a může jej zasáhnout raycast.
user_data a GameMaker instance#
body.set_user_data({kind:"Door", id:17});
var data = body.get_user_data();user_data je čistě high-level GML hodnota. body.bind_instance(instance, use_as_user_data=true) sváže existující instanci a standardně ji uloží i jako user_data. body.sync() explicitně zapíše x, y, z a jolt_rotation_x/y/z/w; synchronizace není automatická. body.unbind_instance() vazbu odstraní. jolt_box_create_dynamic_for_instance(instance, width, depth, height, options) vytvoří a rovnou sváže Dynamic Box.
Kontakty#
Po jolt_update() vrací jolt_get_collisions() world eventy s poli type, body_a/body_b, handly a validitou obou bodies, position, normal, penetration_depth, sensor příznaky a user_data_a/user_data_b. Typ je JOLT_COLLISION_ENTER, STAY nebo EXIT.
body.get_collisions() vrací kontakty daného body s poli type, body, other_body, entity, other_entity, other_handle, other_valid, position, normal, penetration_depth a sensor. jolt_get_dropped_collision_count() hlásí eventy zahozené při přeplnění native fronty.
Raycasty#
var hit = jolt_raycast(x1, y1, z1, x2, y2, z2, filter);
var hits = jolt_raycast_all(x1, y1, z1, x2, y2, z2, filter);filter může být JoltLayer, pole vrstev, číselná maska nebo struct {layers:[...], ignore:body}, případně {mask:value, ignore:body}. Bez filtru se testují všechny vrstvy. Hit obsahuje hit, body, body_handle, entity, position, normal, fraction, distance, error_code a error_message. jolt_raycast_all() vrací seřazené pole. Mesh je jednostranný a výchozí raycast ignoruje zadní strany.
Debug Draw#
jolt_debug_enable(true);
jolt_debug_set(JOLT_DEBUG_SHAPES, true);
jolt_debug_set(JOLT_DEBUG_SENSORS, true);
jolt_debug_draw();JOLT_DEBUG_SHAPES kreslí nesenzorová body a sensory vyžadují JOLT_DEBUG_SENSORS. Motion a sleep stavy mají odlišné barvy. Jde o high-level vizualizaci z metadata, nikoli export interního Jolt shape; doporučené místo je poslední 3D pass, například Draw End.
Ověřené limity implementace#
- Native body handly jsou 32bitové generační hodnoty, nikoli pointery.
- Convex přijímá nejvýše 4096 bodů; výsledný hull nejvýše 256 vrcholů.
- Mesh: 65536 vertices a 131072 triangles.
- HeightField: čtvercová mřížka 4..512 samples.
- Compound: nejvýše 64 children.
- .jcol buffer v GML vrstvě: nejvýše 8 MiB.
- Shape cache key: explicitní ASCII řetězec do 255 znaků; velká pole se automaticky nehashují.
Native smoke test pokrývá Dynamic Convex, Static Mesh, Static HeightField, raycasty, Z-up normals, kontakty, layers, sensors, invalid coplanar Convex, odmítnutí Dynamic Mesh, sanitizaci mesh, reusable shapes a stale handly.
Ověřené kontrakty operací#
Následující kontrakty rozlišují jednotky, návratové hodnoty, chyby a životnost podle aktuální implementace. Nevynechávej kontrolu výsledku: false, 0 a undefined mohou mít u různých metod odlišný význam.
| Symbol / vlastník | Signatura | Kontrakt operace |
|---|---|---|
| JoltBody.get_closest_point | JoltBody.get_closest_point(x, y, z) | Světové XYZ m, dotaz jen proti tomuto tělesu; stejný hit/miss snapshot jako jolt_closest_point. Při chybě hit:false s error_code, nikoliv undefined. |
| JoltBody.get_transform | JoltBody.get_transform() | Světový {x, y, z} m / quaternion XYZW / Euler XYZ° / {position, rotation}, dle metody. undefined při chybě. Pozice je origin tělesa, ne COM. |
| JoltBody.get_world_handle | JoltBody.get_world_handle() | Uložený body/world handle pokud valid, jinak 0. Nepřenášej přes destroy či restart světa. |
| JoltBody.set_bottom_radius | JoltBody.set_bottom_radius(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |
| JoltBody.set_depth | JoltBody.set_depth(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |
| JoltBody.set_half_extent | JoltBody.set_half_extent(value) | Boolean; pouze plane, nenulová konečná normála / kladný half extent v m; ostatní parametr zachován. |
| JoltBody.set_height | JoltBody.set_height(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |
| JoltBody.set_heightfield | JoltBody.set_heightfield(heights,width,height,cell_size,cell_size_y=undefined) | Boolean; nahrazuje geometrii pouze convex / mesh / heightfield podle názvu, se stejnou validací jako jolt_shape_* factory. Identita tělesa zůstává. |
| JoltBody.set_mesh | JoltBody.set_mesh(vertices,indices) | Boolean; nahrazuje geometrii pouze convex / mesh / heightfield podle názvu, se stejnou validací jako jolt_shape_* factory. Identita tělesa zůstává. |
| JoltBody.set_normal | JoltBody.set_normal(x,y,z) | Boolean; pouze plane, nenulová konečná normála / kladný half extent v m; ostatní parametr zachován. |
| JoltBody.set_points | JoltBody.set_points(points) | Boolean; nahrazuje geometrii pouze convex / mesh / heightfield podle názvu, se stejnou validací jako jolt_shape_* factory. Identita tělesa zůstává. |
| JoltBody.set_radius | JoltBody.set_radius(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |
| JoltBody.set_shape | JoltBody.set_shape(resource) | Boolean; živý JoltShape/JoltCompound stejného světa, zachová identitu a gameplay nastavení tělesa i COM offset. Static-only geometrie nesmí vytvořit Dynamic/Kinematic. Aktualizuje metadata a debug cache. |
| JoltBody.set_size | JoltBody.set_size(a,b,c=undefined) | Boolean; box plné width/depth/height, capsule/cylinder height/radius, tapered height/top/bottom radius, vše m. Jiné tvary vyžadují jejich specifický setter. |
| JoltBody.set_top_radius | JoltBody.set_top_radius(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |
| JoltBody.set_width | JoltBody.set_width(value) | Boolean; kladný konečný rozměr v m pro odpovídající typ tvaru. Nevhodný typ selže; set_radius na tapered nastaví oba poloměry. Ostatní rozměry se zachovají. |