chore: init
This commit is contained in:
commit
bbd7927086
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# Normalize EOL for all files that Git considers text files.
|
||||||
|
* text=auto eol=lf
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# Godot 4+ specific ignores
|
||||||
|
.godot/
|
||||||
|
/android/
|
21
LICENSE.txt
Normal file
21
LICENSE.txt
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 yusdacra
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
17
README.md
Normal file
17
README.md
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# boid_2d
|
||||||
|
|
||||||
|
Addon for Godot that adds a 2D node for simulating boids / flocking.
|
||||||
|
|
||||||
|
![boids](./resources/boids.gif)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Clone the repository and copy over the addon.
|
||||||
|
Make an inherited scene from `boid.tscn`, add a `Sprite2D` (or whatever visuals you have) and instantiate and spawn many.
|
||||||
|
Checkout the examples on how to use it more.
|
||||||
|
|
||||||
|
## TODO
|
||||||
|
|
||||||
|
- [ ] fix weird spasming behaviour
|
||||||
|
- [ ] improve collision (dont only bounce, maybe follow wall in some conditions etc.)
|
||||||
|
- [ ] improve performance (BoidManager autoload that tracks and manages every boid?)
|
121
addons/boid_2d/boid.gd
Normal file
121
addons/boid_2d/boid.gd
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
extends Area2D
|
||||||
|
class_name Boid
|
||||||
|
|
||||||
|
|
||||||
|
## sets the `RayCast2D` used to detect walls.
|
||||||
|
@export var wallcast: RayCast2D
|
||||||
|
## sets the `Area2D` used for vision (seeing other boids).
|
||||||
|
@export var vision: Area2D
|
||||||
|
## sets the rotate timer, allowing boids to perform random rotations based on the timer's timeout signal.
|
||||||
|
@export var rotate_timer: Timer
|
||||||
|
|
||||||
|
@export_group("properties")
|
||||||
|
## controls the target (max) speed.
|
||||||
|
@export var target_speed := 6.0
|
||||||
|
## controls how much other boids affect this boid.
|
||||||
|
## higher values will make them more dispersed.
|
||||||
|
@export var steer_away_factor := 40
|
||||||
|
## controls whether or not to run collisions before running boid calculations.
|
||||||
|
## enabling this can help reduce boids escaping colliders, especially if they are following something.
|
||||||
|
@export var collide_first := false
|
||||||
|
|
||||||
|
@export_group("follow")
|
||||||
|
## controls which node to try and follow, if any
|
||||||
|
@export var follow_point: Node2D
|
||||||
|
## controls the radius at which the boid will target, instead of the target directly
|
||||||
|
@export var follow_radius := 100.0
|
||||||
|
|
||||||
|
var last_follow_pos: Vector2 = Vector2.ZERO
|
||||||
|
var follow_target: Vector2
|
||||||
|
var speed := target_speed
|
||||||
|
var vel := Vector2.ZERO
|
||||||
|
var boidsSeen: Dictionary = {}
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
assert(wallcast, "boid invalid: wallcast (RayCast3D) not assigned")
|
||||||
|
assert(vision, "boid invalid: vision (Area2D) not assigned")
|
||||||
|
if rotate_timer:
|
||||||
|
rotate_timer.timeout.connect(_on_rotate_timer_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if collide_first:
|
||||||
|
_process_collision()
|
||||||
|
_process_boids()
|
||||||
|
else:
|
||||||
|
_process_boids()
|
||||||
|
_process_collision()
|
||||||
|
# move boid
|
||||||
|
var vel_dir := vel.normalized()
|
||||||
|
# fix if a boid stops by getting seperated and its vel being cancelled at the same time
|
||||||
|
if vel_dir.is_zero_approx(): vel_dir = Vector2.RIGHT
|
||||||
|
vel = vel_dir * speed
|
||||||
|
global_position += vel
|
||||||
|
# rotate boid
|
||||||
|
global_rotation = atan2(vel_dir.y, vel_dir.x)
|
||||||
|
|
||||||
|
|
||||||
|
func _process_boids() -> void:
|
||||||
|
var numOfBoids := boidsSeen.size()
|
||||||
|
var avgVel := Vector2.ZERO
|
||||||
|
var avgPos := Vector2.ZERO
|
||||||
|
var steerAway := Vector2.ZERO
|
||||||
|
if numOfBoids > 0:
|
||||||
|
for boid: Boid in boidsSeen.values():
|
||||||
|
avgVel += boid.vel; avgPos += boid.global_position
|
||||||
|
var dist := boid.global_position - global_position
|
||||||
|
steerAway -= dist * (steer_away_factor / dist.length())
|
||||||
|
|
||||||
|
# apply follow point vel
|
||||||
|
if follow_point:
|
||||||
|
var dist_to_follow := global_position.distance_to(follow_point.global_position)
|
||||||
|
if global_position.distance_to(follow_target) < 10.0 or dist_to_follow > follow_radius:
|
||||||
|
_calc_follow_target()
|
||||||
|
# slow down speed when nearing target
|
||||||
|
speed = maxf(0.0, lerpf(target_speed, 0.0, follow_radius / dist_to_follow))
|
||||||
|
var target_vel := (follow_point.global_position - last_follow_pos) * Engine.physics_ticks_per_second
|
||||||
|
avgVel += target_vel
|
||||||
|
avgPos += follow_target
|
||||||
|
var dist := follow_target - global_position
|
||||||
|
steerAway -= dist * ((steer_away_factor + follow_radius) / dist.length())
|
||||||
|
numOfBoids += 1
|
||||||
|
last_follow_pos = follow_point.global_position
|
||||||
|
|
||||||
|
if numOfBoids > 0:
|
||||||
|
avgVel /= numOfBoids
|
||||||
|
vel += (avgVel - vel) / 2
|
||||||
|
|
||||||
|
avgPos /= numOfBoids
|
||||||
|
vel += avgPos - global_position
|
||||||
|
|
||||||
|
steerAway /= numOfBoids
|
||||||
|
vel += steerAway
|
||||||
|
|
||||||
|
|
||||||
|
func _calc_follow_target() -> void:
|
||||||
|
var follow_vec := follow_point.global_position - global_position
|
||||||
|
var target_length := follow_vec.length() + follow_radius
|
||||||
|
follow_target = global_position + follow_vec.normalized() * target_length
|
||||||
|
|
||||||
|
|
||||||
|
func _process_collision() -> void:
|
||||||
|
wallcast.force_raycast_update()
|
||||||
|
if not wallcast.is_colliding(): return
|
||||||
|
|
||||||
|
var col_normal: Vector2 = wallcast.get_collision_normal()
|
||||||
|
vel = vel.bounce(col_normal)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_vision_area_entered(area: Area2D) -> void:
|
||||||
|
if area == self: return
|
||||||
|
boidsSeen[area.get_instance_id()] = area
|
||||||
|
|
||||||
|
|
||||||
|
func _on_vision_area_exited(area: Area2D) -> void:
|
||||||
|
boidsSeen.erase(area.get_instance_id())
|
||||||
|
|
||||||
|
|
||||||
|
func _on_rotate_timer_timeout() -> void:
|
||||||
|
vel -= Vector2(randf(), randf()) * speed
|
||||||
|
rotate_timer.start()
|
34
addons/boid_2d/boid.tscn
Normal file
34
addons/boid_2d/boid.tscn
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[gd_scene load_steps=4 format=3 uid="uid://bq7s2yf0fohes"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://addons/boid_2d/boid.gd" id="1_xwhwb"]
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ackok"]
|
||||||
|
size = Vector2(32, 16)
|
||||||
|
|
||||||
|
[sub_resource type="RectangleShape2D" id="RectangleShape2D_ipkm3"]
|
||||||
|
size = Vector2(60, 60)
|
||||||
|
|
||||||
|
[node name="Boid" type="Area2D" node_paths=PackedStringArray("wallcast", "vision")]
|
||||||
|
collision_mask = 0
|
||||||
|
monitoring = false
|
||||||
|
script = ExtResource("1_xwhwb")
|
||||||
|
wallcast = NodePath("WallCast")
|
||||||
|
vision = NodePath("Vision")
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
|
||||||
|
shape = SubResource("RectangleShape2D_ackok")
|
||||||
|
|
||||||
|
[node name="WallCast" type="RayCast2D" parent="."]
|
||||||
|
enabled = false
|
||||||
|
target_position = Vector2(50, 0)
|
||||||
|
|
||||||
|
[node name="Vision" type="Area2D" parent="."]
|
||||||
|
collision_layer = 0
|
||||||
|
monitorable = false
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="Vision"]
|
||||||
|
position = Vector2(42, 0)
|
||||||
|
shape = SubResource("RectangleShape2D_ipkm3")
|
||||||
|
|
||||||
|
[connection signal="area_entered" from="Vision" to="." method="_on_vision_area_entered"]
|
||||||
|
[connection signal="area_exited" from="Vision" to="." method="_on_vision_area_exited"]
|
10
addons/boid_2d/boid_2d.gd
Normal file
10
addons/boid_2d/boid_2d.gd
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
@tool
|
||||||
|
extends EditorPlugin
|
||||||
|
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
add_custom_type("Boid2D", "Area2D", preload("boid.gd"), preload("boid_2d.svg"))
|
||||||
|
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
remove_custom_type("Boid2D")
|
78
addons/boid_2d/boid_2d.svg
Normal file
78
addons/boid_2d/boid_2d.svg
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="16"
|
||||||
|
height="16"
|
||||||
|
viewBox="0 0 16 16.000001"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
sodipodi:docname="boid_2d.svg"
|
||||||
|
inkscape:export-filename="..\..\resources\boid_2d.png"
|
||||||
|
inkscape:export-xdpi="768"
|
||||||
|
inkscape:export-ydpi="768"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#ffffff"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="24.544781"
|
||||||
|
inkscape:cx="9.513224"
|
||||||
|
inkscape:cy="4.0538149"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1">
|
||||||
|
<inkscape:grid
|
||||||
|
id="grid1"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1.0000001"
|
||||||
|
empcolor="#0099e5"
|
||||||
|
empopacity="0.30196078"
|
||||||
|
color="#0099e5"
|
||||||
|
opacity="0.14901961"
|
||||||
|
empspacing="5"
|
||||||
|
dotted="false"
|
||||||
|
gridanglex="30"
|
||||||
|
gridanglez="30"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#8da5f3;fill-opacity:1;stroke-width:26.4565;stroke-linejoin:bevel"
|
||||||
|
d="m 1,0.47939285 c 0,0 7,2.33333335 7,2.97323935 0,0.526761 -7,2.860094 -7,2.860094 2.333333,-2.333333 2.333333,-3.5 0,-5.83333335 z"
|
||||||
|
id="path1"
|
||||||
|
sodipodi:nodetypes="cscc" />
|
||||||
|
<path
|
||||||
|
style="fill:#8da5f3;fill-opacity:1;stroke-width:26.4565;stroke-linejoin:bevel"
|
||||||
|
d="m 8.5092732,5.0267612 c 0,0 6.9999998,2.3333333 6.9999998,2.9732393 0,0.526761 -6.9999998,2.8600945 -6.9999998,2.8600945 2.3333328,-2.3333335 2.3333328,-3.5000005 0,-5.8333338 z"
|
||||||
|
id="path2"
|
||||||
|
sodipodi:nodetypes="cscc" />
|
||||||
|
<path
|
||||||
|
style="fill:#8da5f3;fill-opacity:1;stroke-width:26.4565;stroke-linejoin:bevel"
|
||||||
|
d="m 2.4897504,9.4619873 c 0,0 7,2.3333327 7,2.9732387 0,0.526761 -7,2.860095 -7,2.860095 2.333333,-2.333334 2.333333,-3.500001 0,-5.8333337 z"
|
||||||
|
id="path3"
|
||||||
|
sodipodi:nodetypes="cscc" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
38
addons/boid_2d/boid_2d.svg.import
Normal file
38
addons/boid_2d/boid_2d.svg.import
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://c32akbxu1rkj8"
|
||||||
|
path="res://.godot/imported/boid_2d.svg-172f46790795ecd4cef523288fe60368.ctex"
|
||||||
|
metadata={
|
||||||
|
"has_editor_variant": true,
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/boid_2d/boid_2d.svg"
|
||||||
|
dest_files=["res://.godot/imported/boid_2d.svg-172f46790795ecd4cef523288fe60368.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=true
|
||||||
|
editor/convert_colors_with_editor_theme=true
|
7
addons/boid_2d/plugin.cfg
Normal file
7
addons/boid_2d/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
[plugin]
|
||||||
|
|
||||||
|
name="Boid2D"
|
||||||
|
description="Addon for implementing boids / flocking in Godot."
|
||||||
|
author="yusdacra"
|
||||||
|
version="0.1"
|
||||||
|
script="boid_2d.gd"
|
65
examples/boid_2d/example_boid.svg
Normal file
65
examples/boid_2d/example_boid.svg
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
|
||||||
|
<svg
|
||||||
|
width="48"
|
||||||
|
height="24"
|
||||||
|
viewBox="0 0 48 24.000001"
|
||||||
|
version="1.1"
|
||||||
|
id="svg1"
|
||||||
|
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||||
|
sodipodi:docname="example_boid.svg"
|
||||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview
|
||||||
|
id="namedview1"
|
||||||
|
pagecolor="#5d6c8e"
|
||||||
|
bordercolor="#000000"
|
||||||
|
borderopacity="0.25"
|
||||||
|
inkscape:showpageshadow="2"
|
||||||
|
inkscape:pageopacity="0.0"
|
||||||
|
inkscape:pagecheckerboard="0"
|
||||||
|
inkscape:deskcolor="#d1d1d1"
|
||||||
|
inkscape:document-units="px"
|
||||||
|
showgrid="true"
|
||||||
|
inkscape:zoom="17.355781"
|
||||||
|
inkscape:cx="20.886412"
|
||||||
|
inkscape:cy="8.3833737"
|
||||||
|
inkscape:window-width="1858"
|
||||||
|
inkscape:window-height="1057"
|
||||||
|
inkscape:window-x="1912"
|
||||||
|
inkscape:window-y="-8"
|
||||||
|
inkscape:window-maximized="1"
|
||||||
|
inkscape:current-layer="layer1">
|
||||||
|
<inkscape:grid
|
||||||
|
id="grid1"
|
||||||
|
units="px"
|
||||||
|
originx="0"
|
||||||
|
originy="0"
|
||||||
|
spacingx="1"
|
||||||
|
spacingy="1"
|
||||||
|
empcolor="#0099e5"
|
||||||
|
empopacity="0.30196078"
|
||||||
|
color="#0099e5"
|
||||||
|
opacity="0.14901961"
|
||||||
|
empspacing="5"
|
||||||
|
dotted="false"
|
||||||
|
gridanglex="30"
|
||||||
|
gridanglez="30"
|
||||||
|
visible="true" />
|
||||||
|
</sodipodi:namedview>
|
||||||
|
<defs
|
||||||
|
id="defs1" />
|
||||||
|
<g
|
||||||
|
inkscape:label="Layer 1"
|
||||||
|
inkscape:groupmode="layer"
|
||||||
|
id="layer1">
|
||||||
|
<path
|
||||||
|
style="fill:#ffffff;stroke-width:22.677;stroke-linejoin:bevel"
|
||||||
|
d="M 48,12 C 48,-4.9999998e-7 0,0 0,0 c 30,9.9999996 30,14.999999 0,23.999999 0,0 48,0 48,-11.999999 z"
|
||||||
|
id="path1"
|
||||||
|
sodipodi:nodetypes="sccs" />
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.8 KiB |
37
examples/boid_2d/example_boid.svg.import
Normal file
37
examples/boid_2d/example_boid.svg.import
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://rk5u1wthr0n0"
|
||||||
|
path="res://.godot/imported/example_boid.svg-ebae3589d3b59182aead052ab0bb5c16.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://examples/boid_2d/example_boid.svg"
|
||||||
|
dest_files=["res://.godot/imported/example_boid.svg-ebae3589d3b59182aead052ab0bb5c16.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=6.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
15
examples/boid_2d/example_boid.tscn
Normal file
15
examples/boid_2d/example_boid.tscn
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://bcyffgnn2ahl3"]
|
||||||
|
|
||||||
|
[ext_resource type="PackedScene" uid="uid://bq7s2yf0fohes" path="res://addons/boid_2d/boid.tscn" id="1_825c0"]
|
||||||
|
[ext_resource type="Texture2D" uid="uid://rk5u1wthr0n0" path="res://examples/boid_2d/example_boid.svg" id="2_qfbgc"]
|
||||||
|
|
||||||
|
[node name="Boid" instance=ExtResource("1_825c0")]
|
||||||
|
collision_layer = 2
|
||||||
|
|
||||||
|
[node name="Vision" parent="." index="2"]
|
||||||
|
collision_mask = 2
|
||||||
|
|
||||||
|
[node name="Sprite2D" type="Sprite2D" parent="." index="3"]
|
||||||
|
position = Vector2(-2.17226e-06, 2.38419e-07)
|
||||||
|
scale = Vector2(0.111111, 0.111111)
|
||||||
|
texture = ExtResource("2_qfbgc")
|
18
examples/boid_2d/follow/example.gd
Normal file
18
examples/boid_2d/follow/example.gd
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
for i in 40: spawnBoid()
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
$Path2D/PathFollow2D.progress_ratio += delta * 0.1
|
||||||
|
|
||||||
|
|
||||||
|
func spawnBoid() -> void:
|
||||||
|
var boid: Boid = preload("../example_boid.tscn").instantiate()
|
||||||
|
var screensize := get_viewport_rect().size
|
||||||
|
boid.modulate = Color(randf(), randf(), randf(), 1)
|
||||||
|
boid.global_position = Vector2((randf_range(200, screensize.x - 200)), (randf_range(200, screensize.y - 200)))
|
||||||
|
boid.follow_point = $Path2D/PathFollow2D
|
||||||
|
add_child(boid)
|
19
examples/boid_2d/follow/example.tscn
Normal file
19
examples/boid_2d/follow/example.tscn
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[gd_scene load_steps=3 format=3 uid="uid://ckc0dhvrksfh4"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://examples/boid_2d/follow/example.gd" id="1_cb4mx"]
|
||||||
|
|
||||||
|
[sub_resource type="Curve2D" id="Curve2D_ncwi0"]
|
||||||
|
_data = {
|
||||||
|
"points": PackedVector2Array(69.2957, 57.9564, -69.2957, -57.9564, 1117, 34, 79.375, -118.433, -79.375, 118.433, 34, 28, -61.7361, -114.653, 61.7361, 114.653, 22, 624, -42.8373, 69.2957, 42.8373, -69.2957, 1126, 622, 66.7758, 73.0754, -66.7758, -73.0754, 1117, 34)
|
||||||
|
}
|
||||||
|
point_count = 5
|
||||||
|
|
||||||
|
[node name="Example" type="Node2D"]
|
||||||
|
script = ExtResource("1_cb4mx")
|
||||||
|
|
||||||
|
[node name="Path2D" type="Path2D" parent="."]
|
||||||
|
curve = SubResource("Curve2D_ncwi0")
|
||||||
|
|
||||||
|
[node name="PathFollow2D" type="PathFollow2D" parent="Path2D"]
|
||||||
|
position = Vector2(1117, 34)
|
||||||
|
rotation = -2.44507
|
13
examples/boid_2d/simple/example.gd
Normal file
13
examples/boid_2d/simple/example.gd
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
for i in 100: spawnBoid()
|
||||||
|
|
||||||
|
|
||||||
|
func spawnBoid() -> void:
|
||||||
|
var boid: Boid = preload("../example_boid.tscn").instantiate()
|
||||||
|
var screensize := get_viewport_rect().size
|
||||||
|
boid.modulate = Color(randf(), randf(), randf(), 1)
|
||||||
|
boid.global_position = Vector2((randf_range(200, screensize.x - 200)), (randf_range(200, screensize.y - 200)))
|
||||||
|
add_child(boid)
|
12
examples/boid_2d/simple/example.tscn
Normal file
12
examples/boid_2d/simple/example.tscn
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
[gd_scene load_steps=2 format=3 uid="uid://op0qicvpbjt6"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://examples/boid_2d/simple/example.gd" id="1_3gcrf"]
|
||||||
|
|
||||||
|
[node name="Example" type="Node2D"]
|
||||||
|
script = ExtResource("1_3gcrf")
|
||||||
|
|
||||||
|
[node name="StaticBody2D" type="StaticBody2D" parent="."]
|
||||||
|
collision_priority = 4.0
|
||||||
|
|
||||||
|
[node name="CollisionPolygon2D" type="CollisionPolygon2D" parent="StaticBody2D"]
|
||||||
|
polygon = PackedVector2Array(1152, 0, 1152, 648, 0, 648, 0, 0, 1088, 0, 1088, 64, 64, 64, 64, 576, 1088, 576, 1088, 0)
|
24
project.godot
Normal file
24
project.godot
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
; Engine configuration file.
|
||||||
|
; It's best edited using the editor UI and not directly,
|
||||||
|
; since the parameters that go here are not all obvious.
|
||||||
|
;
|
||||||
|
; Format:
|
||||||
|
; [section] ; section goes between []
|
||||||
|
; param=value ; assign values to parameters
|
||||||
|
|
||||||
|
config_version=5
|
||||||
|
|
||||||
|
[application]
|
||||||
|
|
||||||
|
config/name="Boid Addon"
|
||||||
|
run/main_scene="res://examples/boid_2d/simple/example.tscn"
|
||||||
|
config/features=PackedStringArray("4.3", "GL Compatibility")
|
||||||
|
|
||||||
|
[editor_plugins]
|
||||||
|
|
||||||
|
enabled=PackedStringArray("res://addons/boid_2d/plugin.cfg")
|
||||||
|
|
||||||
|
[rendering]
|
||||||
|
|
||||||
|
renderer/rendering_method="gl_compatibility"
|
||||||
|
renderer/rendering_method.mobile="gl_compatibility"
|
BIN
resources/boid_2d.png
Normal file
BIN
resources/boid_2d.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
34
resources/boid_2d.png.import
Normal file
34
resources/boid_2d.png.import
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://cp6l2f1oac4ce"
|
||||||
|
path="res://.godot/imported/boid_2d.png-b56b7a427c09dbbdb1e601cb745d4254.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://resources/boid_2d.png"
|
||||||
|
dest_files=["res://.godot/imported/boid_2d.png-b56b7a427c09dbbdb1e601cb745d4254.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
BIN
resources/boids.gif
Normal file
BIN
resources/boids.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
Loading…
Reference in New Issue
Block a user