Skip to content

Commit

Permalink
Merge pull request #159 from mphe/collision_optimization
Browse files Browse the repository at this point in the history
Optimize collision generation performance
  • Loading branch information
limbonaut authored Jun 21, 2024
2 parents 8acfa4e + a22a449 commit e152ec9
Show file tree
Hide file tree
Showing 5 changed files with 2,551 additions and 11 deletions.
10 changes: 10 additions & 0 deletions addons/rmsmartshape/documentation/Shapes.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ A shape can be open or closed. Each new shape starts open. To close a shape, sim
- Second Param in Curve2D.tessellate.
- See [Curve2D Documentation](https://docs.godotengine.org/en/3.2/classes/class_curve2d.html#class-curve2d-method-tessellate).

### Collision Generation Method

- Controls which method should be used to generate the collision shape.
- See also in-engine documentation.

### Collision Update Mode

- Controls when to update collisions.
- See also in-engine documentation.

### Curve Bake Interval

- Bake interval value for Curve2D.
Expand Down
6 changes: 3 additions & 3 deletions addons/rmsmartshape/shapes/point_array.gd
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ enum CONSTRAINT { NONE = 0, AXIS_X = 1, AXIS_Y = 2, CONTROL_POINTS = 4, PROPERTI
## Controls how many subdivisions a curve segment may face before it is considered
## approximate enough.
@export_range(0, 8, 1)
var tessellation_stages: int = 5 : set = set_tessellation_stages
var tessellation_stages: int = 3 : set = set_tessellation_stages

## Controls how many degrees the midpoint of a segment may deviate from the real
## curve, before the segment has to be subdivided.
@export_range(0.1, 8.0, 0.1, "or_greater", "or_lesser")
var tessellation_tolerance: float = 4.0 : set = set_tessellation_tolerance
@export_range(0.1, 16.0, 0.1, "or_greater", "or_lesser")
var tessellation_tolerance: float = 6.0 : set = set_tessellation_tolerance

@export_range(1, 512) var curve_bake_interval: float = 20.0 : set = set_curve_bake_interval

Expand Down
69 changes: 62 additions & 7 deletions addons/rmsmartshape/shapes/shape.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ class_name SS2D_Shape
#
# To use search to jump between categories, use the regex: # .+ #

const TUP = preload("../lib/tuple.gd")

################
#-DECLARATIONS-#
################
Expand All @@ -33,6 +31,30 @@ signal make_unique_pressed(shape: SS2D_Shape)

enum ORIENTATION { COLINEAR, CLOCKWISE, C_CLOCKWISE }

enum CollisionGenerationMethod {
## Uses the shape curve to generate a collision polygon. Usually this method is accurate enough.
Fast,
## Uses the edge generation algorithm to create an accurate collision representation that
## exactly matches the shape's visuals.
## Depending on the shape's complexity, this method is very expensive.
Precise,
}

enum CollisionUpdateMode {
## Only update collisions in editor. If the corresponding CollisionPolygon2D is part of the same
## scene, it will be saved automatically by Godot, hence no additional regeneration at runtime
## is necessary, which reduces the loading times.
## Does not work if the CollisionPolygon2D is part of an instanced scene, as only the scene root
## node will be saved by Godot.
Editor,
## Only update collisions during runtime. Improves the shape-editing performance in editor but
## increases loading times as collision generation is deferred to runtime.
Runtime,
## Update collisions both in editor and during runtime. This is the default behavior in older
## SS2D versions.
EditorAndRuntime,
}

###########
#-EXPORTS-#
###########
Expand Down Expand Up @@ -88,20 +110,26 @@ enum ORIENTATION { COLINEAR, CLOCKWISE, C_CLOCKWISE }
## approximate enough.
## @deprecated
@export_range(0, 8, 1)
var tessellation_stages: int = 5 :
var tessellation_stages: int = 3 :
set(value): _points.tessellation_stages = value
get: return _points.tessellation_stages

## Controls how many degrees the midpoint of a segment may deviate from the real
## curve, before the segment has to be subdivided.
## @deprecated
@export_range(0.1, 8.0, 0.1, "or_greater", "or_lesser")
var tessellation_tolerence: float = 4.0 :
@export_range(0.1, 16.0, 0.1, "or_greater", "or_lesser")
var tessellation_tolerence: float = 6.0 :
set(value): _points.tessellation_tolerance = value
get: return _points.tessellation_tolerance

@export_group("Collision")

## Controls which method should be used to generate the collision shape.
@export var collision_generation_method := CollisionGenerationMethod.Fast : set = set_collision_generation_method

## Controls when to update collisions.
@export var collision_update_mode := CollisionUpdateMode.Editor : set = set_collision_update_mode

## Controls size of generated polygon for CollisionPolygon2D.
@export_range(0.0, 64.0, 1.0, "or_greater")
var collision_size: float = 32 : set = set_collision_size
Expand Down Expand Up @@ -180,6 +208,16 @@ func set_render_edges(b: bool) -> void:
notify_property_list_changed()


func set_collision_generation_method(value: CollisionGenerationMethod) -> void:
collision_generation_method = value
set_as_dirty()


func set_collision_update_mode(value: CollisionUpdateMode) -> void:
collision_update_mode = value
set_as_dirty()


func set_collision_size(s: float) -> void:
collision_size = s
set_as_dirty()
Expand Down Expand Up @@ -815,7 +853,7 @@ func should_flip_edges() -> bool:
return flip_edges


func generate_collision_points() -> PackedVector2Array:
func _generate_collision_points_precise() -> PackedVector2Array:
var points := PackedVector2Array()
var num_points: int = _points.get_point_count()
if num_points < 2:
Expand Down Expand Up @@ -861,11 +899,28 @@ func generate_collision_points() -> PackedVector2Array:
return points


func _generate_collision_points_fast() -> PackedVector2Array:
return _points.get_tessellated_points()


func bake_collision() -> void:
if not _collision_polygon_node:
return

if collision_update_mode == CollisionUpdateMode.Editor and not Engine.is_editor_hint() \
or collision_update_mode == CollisionUpdateMode.Runtime and Engine.is_editor_hint():
return

var generated_points: PackedVector2Array

match collision_generation_method:
CollisionGenerationMethod.Fast:
generated_points = _generate_collision_points_fast()
CollisionGenerationMethod.Precise:
generated_points = _generate_collision_points_precise()

var xform := _collision_polygon_node.get_global_transform().affine_inverse() * get_global_transform()
_collision_polygon_node.polygon = xform * generate_collision_points()
_collision_polygon_node.polygon = xform * generated_points


func cache_edges() -> void:
Expand Down
Loading

0 comments on commit e152ec9

Please sign in to comment.