From ac9934463366eac3eff203bcbafd005aba6e5cf0 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Wed, 8 Jan 2020 12:46:42 -0500 Subject: [PATCH] Implement Separation behavior and add Proximity --- project/project.godot | 24 +++++++++++ project/src/behaviors/GSTSeparation.gd | 40 +++++++++++++++++++ .../src/proximities/GSTInfiniteProximity.gd | 20 ++++++++++ project/src/proximities/GSTProximity.gd | 16 ++++++++ project/src/proximities/GSTRadiusProximity.gd | 33 +++++++++++++++ 5 files changed, 133 insertions(+) create mode 100644 project/src/behaviors/GSTSeparation.gd create mode 100644 project/src/proximities/GSTInfiniteProximity.gd create mode 100644 project/src/proximities/GSTProximity.gd create mode 100644 project/src/proximities/GSTRadiusProximity.gd diff --git a/project/project.godot b/project/project.godot index 45baf3a..173cce5 100644 --- a/project/project.godot +++ b/project/project.godot @@ -39,6 +39,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/behaviors/GSTFlee.gd" }, { +"base": "GSTProximity", +"class": "GSTInfiniteProximity", +"language": "GDScript", +"path": "res://src/proximities/GSTInfiniteProximity.gd" +}, { "base": "GSTMatchOrientation", "class": "GSTLookWhereYouGo", "language": "GDScript", @@ -54,16 +59,31 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/behaviors/GSTPriority.gd" }, { +"base": "Reference", +"class": "GSTProximity", +"language": "GDScript", +"path": "res://src/proximities/GSTProximity.gd" +}, { "base": "GSTSteeringBehavior", "class": "GSTPursue", "language": "GDScript", "path": "res://src/behaviors/GSTPursue.gd" }, { +"base": "GSTProximity", +"class": "GSTRadiusProximity", +"language": "GDScript", +"path": "res://src/proximities/GSTRadiusProximity.gd" +}, { "base": "GSTSteeringBehavior", "class": "GSTSeek", "language": "GDScript", "path": "res://src/behaviors/GSTSeek.gd" }, { +"base": "GSTSteeringBehavior", +"class": "GSTSeparation", +"language": "GDScript", +"path": "res://src/behaviors/GSTSeparation.gd" +}, { "base": "GSTAgentLocation", "class": "GSTSteeringAgent", "language": "GDScript", @@ -91,11 +111,15 @@ _global_script_class_icons={ "GSTEvade": "", "GSTFace": "", "GSTFlee": "", +"GSTInfiniteProximity": "", "GSTLookWhereYouGo": "", "GSTMatchOrientation": "", "GSTPriority": "", +"GSTProximity": "", "GSTPursue": "", +"GSTRadiusProximity": "", "GSTSeek": "", +"GSTSeparation": "", "GSTSteeringAgent": "", "GSTSteeringBehavior": "", "GSTTargetAcceleration": "", diff --git a/project/src/behaviors/GSTSeparation.gd b/project/src/behaviors/GSTSeparation.gd new file mode 100644 index 0000000..f7fcf67 --- /dev/null +++ b/project/src/behaviors/GSTSeparation.gd @@ -0,0 +1,40 @@ +extends GSTSteeringBehavior +class_name GSTSeparation +# Group behavior that produces acceleration repelling from the other neighbors that are in the +# immediate area defined by the given `GSTProximity`. + +# # The produced acceleration is an average of all agents under consideration, multiplied by a +# # strength decreasing by the inverse square law in relation to distance, and accumulated. +# # In effect, all neighbors produce a single repelling force. + + +var decay_coefficient: = 1.0 + +var acceleration: GSTTargetAcceleration +var proximity: GSTProximity + + +func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent) -> void: + self.proximity = proximity + + +func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: + acceleration.set_zero() + self.acceleration = acceleration + proximity.find_neighbors(funcref(self, "_report_neighbor")) + return acceleration + + +func _report_neighbor(neighbor: GSTSteeringAgent) -> bool: + var to_agent: = agent.position - neighbor.position + + var distance_squared: = to_agent.length_squared() + var max_acceleration: = agent.max_linear_acceleration + + var strength: = decay_coefficient / distance_squared + if strength > max_acceleration: + strength = max_acceleration + + acceleration.linear += to_agent * (strength / sqrt(distance_squared)) + + return true diff --git a/project/src/proximities/GSTInfiniteProximity.gd b/project/src/proximities/GSTInfiniteProximity.gd new file mode 100644 index 0000000..07ffbfd --- /dev/null +++ b/project/src/proximities/GSTInfiniteProximity.gd @@ -0,0 +1,20 @@ +extends GSTProximity +class_name GSTInfiniteProximity +# Specifies any agent that is in the specified list as being neighbors with the owner agent. + + +func _init(agent: GSTSteeringAgent, agents: Array).(agent, agents) -> void: + pass + + +func find_neighbors(callback: FuncRef) -> int: + var neighbor_count: = 0 + var agent_count: = agents.size() + for i in range(agent_count): + var current_agent: = agents[i] as GSTSteeringAgent + + if current_agent != agent: + if callback.call_func(current_agent): + neighbor_count += 1 + + return neighbor_count diff --git a/project/src/proximities/GSTProximity.gd b/project/src/proximities/GSTProximity.gd new file mode 100644 index 0000000..36410ee --- /dev/null +++ b/project/src/proximities/GSTProximity.gd @@ -0,0 +1,16 @@ +extends Reference +class_name GSTProximity +# Defines an area that is used by group behaviors to find and process the owner's neighbors. + + +var agent: GSTSteeringAgent +var agents: = [] + + +func _init(agent: GSTSteeringAgent, agents: Array) -> void: + self.agent = agent + self.agents = agents + + +func find_neighbors(callback: FuncRef) -> int: + return 0 \ No newline at end of file diff --git a/project/src/proximities/GSTRadiusProximity.gd b/project/src/proximities/GSTRadiusProximity.gd new file mode 100644 index 0000000..3014399 --- /dev/null +++ b/project/src/proximities/GSTRadiusProximity.gd @@ -0,0 +1,33 @@ +extends GSTProximity +class_name GSTRadiusProximity +# Specifies any agent that is in the specified list as being neighbors with the owner agent if they +# lie within the specified radius. + + +var radius: = 0.0 + + +func _init(agent: GSTSteeringAgent, agents: Array, radius: float).(agent, agents) -> void: + self.radius = radius + + +func find_neighbors(callback: FuncRef) -> int: + var agent_count: = agents.size() + var neighbor_count: = 0 + + var owner_position: = agent.position + + for i in range(agent_count): + var current_agent: = agents[i] as GSTSteeringAgent + + if current_agent != agent: + var distance_squared: = owner_position.distance_squared_to(current_agent.position) + + var range_to: = radius + current_agent.bounding_radius + + if distance_squared < range_to * range_to: + if callback.call_func(current_agent) == true: + neighbor_count += 1 + continue + + return neighbor_count