From 34b58a6bba98c3a8e0700e2312f023a793e7a561 Mon Sep 17 00:00:00 2001 From: Francois Belair Date: Thu, 9 Jan 2020 12:24:55 -0500 Subject: [PATCH] Add Cohesion behavior and RadiusProximity caching --- project/project.godot | 24 +++++++++++ project/src/GSTSteeringAgent.gd | 1 + project/src/behaviors/GSTCohesion.gd | 27 ++++++++++++ project/src/proximities/GSTProximity.gd | 32 +++++++------- project/src/proximities/GSTRadiusProximity.gd | 42 +++++++++++++------ 5 files changed, 98 insertions(+), 28 deletions(-) create mode 100644 project/src/behaviors/GSTCohesion.gd diff --git a/project/project.godot b/project/project.godot index 173cce5..c5b5251 100644 --- a/project/project.godot +++ b/project/project.godot @@ -20,10 +20,20 @@ _global_script_classes=[ { "path": "res://src/behaviors/GSTArrive.gd" }, { "base": "GSTSteeringBehavior", +"class": "GSTAvoidCollisions", +"language": "GDScript", +"path": "res://src/behaviors/GSTAvoidCollisions.gd" +}, { +"base": "GSTSteeringBehavior", "class": "GSTBlend", "language": "GDScript", "path": "res://src/behaviors/GSTBlend.gd" }, { +"base": "GSTSteeringBehavior", +"class": "GSTCohesion", +"language": "GDScript", +"path": "res://src/behaviors/GSTCohesion.gd" +}, { "base": "GSTPursue", "class": "GSTEvade", "language": "GDScript", @@ -39,6 +49,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/behaviors/GSTFlee.gd" }, { +"base": "GSTArrive", +"class": "GSTFollowPath", +"language": "GDScript", +"path": "res://src/behaviors/GSTFollowPath.gd" +}, { "base": "GSTProximity", "class": "GSTInfiniteProximity", "language": "GDScript", @@ -54,6 +69,11 @@ _global_script_classes=[ { "language": "GDScript", "path": "res://src/behaviors/GSTMatchOrientation.gd" }, { +"base": "Reference", +"class": "GSTPath", +"language": "GDScript", +"path": "res://src/GSTPath.gd" +}, { "base": "GSTSteeringBehavior", "class": "GSTPriority", "language": "GDScript", @@ -107,13 +127,17 @@ _global_script_classes=[ { _global_script_class_icons={ "GSTAgentLocation": "", "GSTArrive": "", +"GSTAvoidCollisions": "", "GSTBlend": "", +"GSTCohesion": "", "GSTEvade": "", "GSTFace": "", "GSTFlee": "", +"GSTFollowPath": "", "GSTInfiniteProximity": "", "GSTLookWhereYouGo": "", "GSTMatchOrientation": "", +"GSTPath": "", "GSTPriority": "", "GSTProximity": "", "GSTPursue": "", diff --git a/project/src/GSTSteeringAgent.gd b/project/src/GSTSteeringAgent.gd index 17b34b6..c8a17b9 100644 --- a/project/src/GSTSteeringAgent.gd +++ b/project/src/GSTSteeringAgent.gd @@ -11,3 +11,4 @@ var max_angular_acceleration: = 0.0 var linear_velocity: = Vector3.ZERO var angular_velocity: = 0.0 var bounding_radius: = 0.0 +var tagged: = false diff --git a/project/src/behaviors/GSTCohesion.gd b/project/src/behaviors/GSTCohesion.gd new file mode 100644 index 0000000..08cecee --- /dev/null +++ b/project/src/behaviors/GSTCohesion.gd @@ -0,0 +1,27 @@ +extends GSTSteeringBehavior +class_name GSTCohesion +# Group behavior that produces linear acceleration that attempts to move the agent towards the +# center of mass of the agents in the area defined by the defined Proximity. + + +var center_of_mass: Vector3 +var proximity: GSTProximity + + +func _init(agent: GSTSteeringAgent, proximity: GSTProximity).(agent) -> void: + self.proximity = proximity + + +func _calculate_steering(acceleration: GSTTargetAcceleration) -> GSTTargetAcceleration: + acceleration.set_zero() + center_of_mass = Vector3.ZERO + var neighbor_count = proximity.find_neighbors(funcref(self, "_report_neighbor")) + if neighbor_count > 0: + center_of_mass *= 1.0 / neighbor_count + acceleration.linear = (center_of_mass - agent.position).normalized() * agent.max_linear_acceleration + return acceleration + + +func _report_neighbor(neighbor: GSTSteeringAgent) -> bool: + center_of_mass += neighbor.position + return true diff --git a/project/src/proximities/GSTProximity.gd b/project/src/proximities/GSTProximity.gd index 36410ee..9eb5f9d 100644 --- a/project/src/proximities/GSTProximity.gd +++ b/project/src/proximities/GSTProximity.gd @@ -1,16 +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 +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 diff --git a/project/src/proximities/GSTRadiusProximity.gd b/project/src/proximities/GSTRadiusProximity.gd index 3014399..2e5bbd8 100644 --- a/project/src/proximities/GSTRadiusProximity.gd +++ b/project/src/proximities/GSTRadiusProximity.gd @@ -6,28 +6,46 @@ class_name GSTRadiusProximity var radius: = 0.0 +var _last_frame: = 0 +var _scene_tree: SceneTree + func _init(agent: GSTSteeringAgent, agents: Array, radius: float).(agent, agents) -> void: self.radius = radius + _scene_tree = Engine.get_main_loop() 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: + var current_frame: = _scene_tree.get_frame() if _scene_tree else -_last_frame + if current_frame != _last_frame: + _last_frame = current_frame + + 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: + current_agent.tagged = true + neighbor_count += 1 + continue + + current_agent.tagged = false + else: + for i in range(agent_count): + var current_agent = agents[i] as GSTSteeringAgent + + if current_agent != agent and current_agent.tagged: if callback.call_func(current_agent) == true: neighbor_count += 1 - continue return neighbor_count