Skip to content

Instantly share code, notes, and snippets.

@Shilo
Last active October 24, 2023 15:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shilo/c2a8cc05d131432f3b8c5f237acc413b to your computer and use it in GitHub Desktop.
Save Shilo/c2a8cc05d131432f3b8c5f237acc413b to your computer and use it in GitHub Desktop.
Godot tool for auto syncing position and size of collision shape 3d with a target mesh instance 3d. (GDScript or C#)
@tool
class_name AutoCollisionShape3DGD extends CollisionShape3D
@export var mesh_instance_3d: MeshInstance3D
@export_group("Editor Auto Sync")
@export var auto_sync_position_editor: bool = true
@export var auto_sync_size_editor: bool = true
@export_group("Editor Gizmo [EXPERIMENTAL]")
@export var scale_to_shape: bool = false
@export var scale_sensitivity: float = 0.25
@export_group("Runtime")
@export var destroy_script_in_runtime: bool = true
func _enter_tree():
if destroy_script_in_runtime && !Engine.is_editor_hint():
set_script(null)
func _process(_delta):
_process_auto_sync()
_process_gizmo()
func _process_auto_sync():
if !mesh_instance_3d:
return
if !mesh_instance_3d.is_inside_tree():
mesh_instance_3d = null
return
if auto_sync_position_editor:
global_position = mesh_instance_3d.global_position
if auto_sync_size_editor:
scale = Vector3.ONE
if shape && shape is BoxShape3D && mesh_instance_3d.mesh:
shape.size = mesh_instance_3d.mesh.get_aabb().size
if !_is_mesh_instance_ancestor():
shape.size *= mesh_instance_3d.global_transform.basis
# TODO: handle rotation if not child of mesh instance
func _process_gizmo():
if !scale_to_shape || !shape:
return
if scale != Vector3.ONE:
shape.size *= (scale - Vector3.ONE) * scale_sensitivity + Vector3.ONE
scale = Vector3.ONE
func _is_mesh_instance_ancestor() -> bool:
var parent = get_parent()
while parent:
if parent == mesh_instance_3d:
return true
parent = parent.get_parent()
return false
using Godot;
[Tool, GlobalClass]
public partial class AutoCollisionShape3D : CollisionShape3D
{
[Export]
public MeshInstance3D MeshInstance;
[ExportGroup("Editor Auto Sync")]
[Export]
public bool AutoSyncPositionEditor = true;
[Export]
public bool AutoSyncSizeEditor = true;
[ExportGroup("Editor Gizmo [EXPERIMENTAL]")]
[Export]
public bool ScaleToShape = false;
[Export]
public float ScaleSensitivity = 0.25f;
[ExportGroup("Runtime")]
[Export]
public bool DestroyScriptInRuntime = true;
public override void _EnterTree()
{
if (DestroyScriptInRuntime && !Engine.IsEditorHint())
SetScript(new Variant());
}
public override void _Process(double delta)
{
_ProcessAutoSync();
_ProcessGizmo();
}
private void _ProcessAutoSync()
{
if (MeshInstance == null)
return;
if (!MeshInstance.IsInsideTree())
{
MeshInstance = null;
return;
}
if (AutoSyncPositionEditor)
GlobalPosition = MeshInstance.GlobalPosition;
if (AutoSyncSizeEditor)
{
Scale = Vector3.One;
if (Shape != null && Shape is BoxShape3D && MeshInstance.Mesh != null)
{
var boxShape = Shape as BoxShape3D;
boxShape.Size = MeshInstance.Mesh.GetAabb().Size;
if (!_IsMeshInstanceAncestor())
{
boxShape.Size *= MeshInstance.GlobalTransform.Basis;
// TODO: handle rotation if not child of mesh instance
}
}
}
}
private void _ProcessGizmo()
{
if (!ScaleToShape || Shape == null)
return;
if (Scale != Vector3.One && Shape is BoxShape3D)
{
(Shape as BoxShape3D).Size *= (Scale - Vector3.One) * ScaleSensitivity + Vector3.One;
Scale = Vector3.One;
}
}
private bool _IsMeshInstanceAncestor()
{
Node parent = GetParent();
while (parent != null)
{
if (parent == MeshInstance)
return true;
parent = parent.GetParent();
}
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment