105 lines
3.5 KiB
GDScript
105 lines
3.5 KiB
GDScript
### Supports [CollisionObject2D], [Joint2D] and [CollisionShape2D].
|
|
@icon("res://addons/godot-rapier2d/logo_square_2d.png")
|
|
class_name Rapier2DState
|
|
extends Node
|
|
|
|
var state: Dictionary = {}
|
|
|
|
|
|
func _is_physics_object(node: Node) -> bool:
|
|
return node is CollisionObject2D or node is Joint2D
|
|
|
|
|
|
func _get_all_physics_nodes(p_node: Node, path: String = "/root/") -> Array[String]:
|
|
var results: Array[String] = []
|
|
if path == "/root/" && _is_physics_object(p_node):
|
|
results.append(path + p_node.name)
|
|
path += p_node.name + "/"
|
|
for node in p_node.get_children():
|
|
if _is_physics_object(node):
|
|
results.append(path + node.name)
|
|
if node.get_child_count() > 0:
|
|
results.append_array(_get_all_physics_nodes(node, path))
|
|
return results
|
|
|
|
|
|
## Save a node's physics state
|
|
func save_node(rid: RID, save_json: bool):
|
|
if save_json:
|
|
return JSON.parse_string(RapierPhysicsServer2D.export_json(rid))
|
|
return RapierPhysicsServer2D.export_binary(rid)
|
|
|
|
|
|
## Load a node's physics state
|
|
func load_node(rid: RID, data: PackedByteArray):
|
|
RapierPhysicsServer2D.import_binary(rid, data)
|
|
|
|
|
|
## Save the state of whole world (single space)
|
|
func save_state(save_json: bool = false) -> int:
|
|
var physics_nodes := _get_all_physics_nodes(get_tree().current_scene)
|
|
for node_path in physics_nodes:
|
|
var node := get_node(node_path)
|
|
var rid: RID
|
|
if node is CollisionObject2D:
|
|
rid = node.get_rid()
|
|
for owner_id in node.get_shape_owners():
|
|
for owner_shape_id in node.shape_owner_get_shape_count(owner_id):
|
|
var shape_rid = node.shape_owner_get_shape(owner_id, owner_shape_id).get_rid()
|
|
state[node_path + "/" + str(owner_id) + "/" + str(owner_shape_id)] = save_node(
|
|
shape_rid, save_json
|
|
)
|
|
if node is Joint2D:
|
|
rid = node.get_rid()
|
|
state[node_path] = save_node(rid, save_json)
|
|
var space_rid = get_viewport().world_2d.space
|
|
state["space"] = save_node(space_rid, save_json)
|
|
state["id"] = RapierPhysicsServer2D.get_global_id()
|
|
return hash(JSON.stringify(state))
|
|
|
|
|
|
## Load the state of whole world (single space)
|
|
func load_state() -> int:
|
|
var physics_nodes := _get_all_physics_nodes(get_tree().current_scene)
|
|
for node_path in physics_nodes:
|
|
var node := get_node(node_path)
|
|
var rid: RID
|
|
if node is CollisionObject2D:
|
|
rid = node.get_rid()
|
|
for owner_id in node.get_shape_owners():
|
|
for owner_shape_id in node.shape_owner_get_shape_count(owner_id):
|
|
var shape_rid = node.shape_owner_get_shape(owner_id, owner_shape_id).get_rid()
|
|
var shape_state = state[
|
|
node_path + "/" + str(owner_id) + "/" + str(owner_shape_id)
|
|
]
|
|
load_node(shape_rid, JSON.parse_string(shape_state))
|
|
if node is Joint2D:
|
|
rid = node.get_rid()
|
|
var node_state = state[node_path]
|
|
load_node(rid, JSON.parse_string(node_state))
|
|
var space_rid = get_viewport().world_2d.space
|
|
load_node(space_rid, JSON.parse_string(state["space"]))
|
|
RapierPhysicsServer2D.set_global_id(int(state["id"]))
|
|
return hash(JSON.stringify(state))
|
|
|
|
|
|
## Export the state to file
|
|
func export_state(file_name: String = "user://state.json"):
|
|
save_state(false)
|
|
FileAccess.open(file_name, FileAccess.WRITE).store_string(JSON.stringify(state, " "))
|
|
|
|
|
|
## Import the state from file
|
|
func import_state(file_name: String = "user://state.json"):
|
|
state = JSON.parse_string(FileAccess.open(file_name, FileAccess.READ).get_as_text())
|
|
load_state()
|
|
|
|
|
|
func _notification(what: int) -> void:
|
|
if what == NOTIFICATION_ENTER_TREE:
|
|
print("enter tree")
|
|
if what == NOTIFICATION_EXIT_TREE:
|
|
save_state(false)
|
|
FileAccess.open("user://save.json", FileAccess.WRITE).store_string(
|
|
JSON.stringify(state, " ")
|
|
)
|