http://www.kfish.org/boids/pseudocode.html
视频教程
源码
- https://github.com/kyrick/godot-boids-acceleration-structure
-
源码链接(3.x):https://github.com/kyrick/godot-boids
演示视频:https://www.youtube.com/watch?v=aCfoX45yF0w
Godot 4.0 stable
点击会向点击位置移动
#============================================================
# Flock
#============================================================
# - author: zhangxuetu
# - datetime: 2023-04-14 21:37:46
# - version: 4.0
#============================================================
class_name Flock
extends Node2D
const GROUP_NAME = "_Flock"
@export var max_speed: = 200.0
@export var mouse_follow_force: = 0.05
@export var cohesion_force: = 0.05
@export var algin_force: = 0.05
@export var separation_force: = 0.05
@export var view_distance: float = 50.0
@export var avoid_distance: float = 20.0
var _width = ProjectSettings.get_setting("display/window/size/viewport_width")
var _height = ProjectSettings.get_setting("display/window/size/viewport_height")
var _flock: Array = []
var _mouse_target: Vector2
var _velocity: Vector2
func _ready():
randomize()
_velocity = Vector2(randf_range(-1, 1), randf_range(-1, 1)).normalized() * max_speed
_mouse_target = get_random_target()
add_to_group(GROUP_NAME)
func _input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT:
_mouse_target = event.position
elif event.button_index == MOUSE_BUTTON_RIGHT:
_mouse_target = get_random_target()
func _physics_process(_delta):
var mouse_vector = Vector2.ZERO
if _mouse_target != Vector2.INF:
mouse_vector = global_position.direction_to(_mouse_target) * max_speed * mouse_follow_force
_flock = get_tree().get_nodes_in_group(GROUP_NAME)
# get cohesion, alginment, and separation vectors
var vectors = get_flock_status(_flock)
# steer towards vectors
var cohesion_vector = vectors[0] * cohesion_force
var align_vector = vectors[1] * algin_force
var separation_vector = vectors[2] * separation_force
var acceleration = cohesion_vector + align_vector + separation_vector + mouse_vector
_velocity = Vector2(_velocity + acceleration).limit_length(max_speed)
_velocity = _velocity * _delta
global_position += _velocity
func get_flock_status(flock: Array):
var center_vector: = Vector2()
var flock_center: = Vector2()
var align_vector: = Vector2()
var avoid_vector: = Vector2()
for f in flock:
var neighbor_pos: Vector2 = f.global_position
align_vector += f._velocity
flock_center += neighbor_pos
var d = global_position.distance_to(neighbor_pos)
if d > 0 and d < avoid_distance:
avoid_vector -= (neighbor_pos - global_position).normalized() * (avoid_distance / d * max_speed)
var flock_size = flock.size()
if flock_size:
align_vector /= flock_size
flock_center /= flock_size
var center_dir = global_position.direction_to(flock_center)
var center_speed = max_speed * (global_position.distance_to(flock_center) / view_distance)
center_vector = center_dir * center_speed
return [center_vector, align_vector, avoid_vector]
func get_random_target():
randomize()
return Vector2(randf_range(0, _width), randf_range(0, _height))