【Godot】鸟群/群集行为

http://www.kfish.org/boids/pseudocode.html


视频教程

  1. https://www.youtube.com/watch?v=pXQCasmBhY4

源码

  1. https://github.com/kyrick/godot-boids-acceleration-structure

  2. 源码链接(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))


发表评论