1
Fork 0
mirror of https://github.com/Steffo99/hella-farm.git synced 2024-11-21 15:44:23 +00:00

Merge pull request #1 from Steffo99/feature/componentized-behaviours

Refactor everything into componentized and reusable behaviours
This commit is contained in:
Lorenzo Rossi 2024-04-22 23:03:08 +02:00 committed by GitHub
commit bacbbb7ff0
Signed by: github
GPG key ID: B5690EEEBB952194
118 changed files with 1970 additions and 993 deletions

18
.vscode/launch.json vendored Normal file
View file

@ -0,0 +1,18 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Launch Project",
"type": "godot",
"request": "launch",
"project": "${workspaceFolder}",
},
{
"name": "Launch Scene",
"type": "godot",
"request": "launch",
"scene": "current",
"project": "${workspaceFolder}",
}
]
}

View file

@ -8,12 +8,12 @@ This project uses the following external assets:
| `./temp/tollbell.mp3` | https://freesound.org/people/sdroliasnick/sounds/731270/ | CC0 |
| `./entities/sheep_drag.wav` | https://freesound.org/people/michaelperfect/sounds/710298/ | CC0 |
| `./temp/click&pop.wav` | https://freesound.org/people/GammaGool/sounds/730488/ | CC0 |
| `./temp/pop.wav` | https://freesound.org/people/NovaSoundTechnology/sounds/727104/ | CC0 |
| `./entities/monocle_drag.wav` | https://freesound.org/people/NovaSoundTechnology/sounds/727104/ | CC0 |
| `./temp/mouth_pop.wav` | https://freesound.org/people/igaopuromalte/sounds/725453/ | Attribution 4 |
| `./temp/puff.wav` | https://freesound.org/people/JustInvoke/sounds/446124/ | Attribution 4 |
| `./entities/fall.ogg` | https://freesound.org/people/JustInvoke/sounds/446124/ | Attribution 4 |
| `./temp/place.wav` | https://freesound.org/people/Planman/sounds/208111/ | CC0 |
| `./temp/gore.wav` | https://freesound.org/people/MinecraftGamerLR/sounds/728695/ | Attribution 4 |
| `./temp/bones.wav` | https://freesound.org/people/cliftonmcarlson/sounds/392883/ | CC0 |
| `./entities/imp_eat.ogg` | https://freesound.org/people/MinecraftGamerLR/sounds/728695/ | Attribution 4 |
| `./entities/skull_pickup.wav` | https://freesound.org/people/cliftonmcarlson/sounds/392883/ | CC0 |
| `./temp/metallic_whistle.wav` | https://freesound.org/people/furbyguy/sounds/365643/| Attribution 3|
| `./temp/upgradeselect.wav` | https://freesound.org/people/TechspiredMinds/sounds/729216/| Attribution 4|
| `./temp/upgrade.wav` | https://freesound.org/people/colorsCrimsonTears/sounds/607409/ | CC0 |
@ -22,7 +22,7 @@ This project uses the following external assets:
| `./temp/arcade_cancel.flac` | https://freesound.org/people/plasterbrain/sounds/464912/ | CC0 |
| `./temp/cancel.wav` | https://freesound.org/people/Kagateni/sounds/571510/ | CC0 |
| `./temp/monster_bite.wav` | https://freesound.org/people/OGsoundFX/sounds/423010/ | Attribution 4 |
| `./temp/tank.wav` | https://freesound.org/people/JarredGibb/sounds/217273/ | CC0 |
| `./entities/imp_drag.wav` | https://freesound.org/people/JarredGibb/sounds/217273/ | CC0 |
| `./temp/demon_dying.wav` | https://freesound.org/people/THE_bizniss/sounds/37823/ | Attribution 3 |
| `./entities/coin.ogg` | https://freesound.org/people/forrisday/sounds/214509/ | Attribution 4 |
| `./behaviours/*.svg` | https://fontawesome.com/ | CC-BY 4.0 |

View file

@ -1,18 +0,0 @@
@icon("res://behaviours/collectable.svg")
extends Area2D
class_name Collectable
## Emits [signal collected] when the mouse enters the given [CollisionShape2D].
signal collected
@export var qty: int = 1
@export var tag: StringName = &""
func _on_mouse_entered() -> void:
collected.emit(tag)
func _on_collected() -> void:
Log.p(self, "Collected: %sx %s" % [qty, tag])

View file

@ -1,9 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://dj72yshd25ucx"]
[ext_resource type="Script" path="res://behaviours/collectable.gd" id="1_p0pc3"]
[node name="Collectable" type="Area2D"]
script = ExtResource("1_p0pc3")
[connection signal="collected" from="." to="." method="_on_collected"]
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]

17
behaviours/collectible.gd Normal file
View file

@ -0,0 +1,17 @@
@icon("res://behaviours/collectible.svg")
extends Node
class_name Collectible
## How many of that item this [Collectible] represents.
@export var quantity: int = 1
## What kind of item this [Collectible] represents.
@export var kind: StringName = &""
@onready var game: MainGame = MainGame.get_via_group(self)
func apply():
game.inventory.get_counter(kind).increase(quantity)

View file

@ -3,7 +3,7 @@
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="hand.svg"
sodipodi:docname="collectable.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
@ -23,8 +23,8 @@
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="1.1642403"
inkscape:cx="350.01366"
inkscape:cy="213.44391"
inkscape:cx="350.01365"
inkscape:cy="-130.12778"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="1280"
@ -35,5 +35,5 @@
<path
d="M 288,32 C 288,14.3 273.7,0 256,0 238.3,0 224,14.3 224,32 v 208 c 0,8.8 -7.2,16 -16,16 -8.8,0 -16,-7.2 -16,-16 V 64 c 0,-17.7 -14.3,-32 -32,-32 -17.7,0 -32,14.3 -32,32 v 272 c 0,1.5 0,3.1 0.1,4.6 L 67.6,283 c -16,-15.2 -41.3,-14.6 -56.6,1.4 -15.3,16 -14.6,41.3 1.4,56.6 l 112.4,107 c 43.1,41.1 100.4,64 160,64 H 304 c 97.2,0 176,-78.8 176,-176 V 128 c 0,-17.7 -14.3,-32 -32,-32 -17.7,0 -32,14.3 -32,32 v 112 c 0,8.8 -7.2,16 -16,16 -8.8,0 -16,-7.2 -16,-16 V 64 c 0,-17.7 -14.3,-32 -32,-32 -17.7,0 -32,14.3 -32,32 v 176 c 0,8.8 -7.2,16 -16,16 -8.8,0 -16,-7.2 -16,-16 z"
id="path1"
style="fill:#8da5f3;fill-opacity:1" />
style="fill:#e0e0e0;fill-opacity:1" />
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://ds6w6y6v8ywg2"
path="res://.godot/imported/collectable.svg-5b05e2ea83b32a2349a97b4d9981d066.ctex"
path="res://.godot/imported/collectible.svg-c540ac452c425e9fd16afd6982ebfbf2.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/collectable.svg"
dest_files=["res://.godot/imported/collectable.svg-5b05e2ea83b32a2349a97b4d9981d066.ctex"]
source_file="res://behaviours/collectible.svg"
dest_files=["res://.godot/imported/collectible.svg-c540ac452c425e9fd16afd6982ebfbf2.ctex"]
[params]

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dj72yshd25ucx"]
[ext_resource type="Script" path="res://behaviours/collectible.gd" id="1_5ipmg"]
[node name="Collectible" type="Node"]
script = ExtResource("1_5ipmg")

View file

@ -0,0 +1,24 @@
@icon("res://behaviours/cursor_detector.svg")
extends Area2D
class_name CursorDetector
signal cursor_entered(cursor: Cursor)
signal cursor_exited(cursor: Cursor)
var mouse_inside = false
func _on_area_entered(body: Area2D) -> void:
if body is Cursor:
mouse_inside = true
cursor_entered.emit(body)
func _on_area_exited(body: Area2D) -> void:
if body is Cursor:
mouse_inside = true
cursor_exited.emit(body)
func log_cursor(cursor: Cursor) -> void:
Log.p(self, "Cursor: %s" % cursor)

View file

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://6wpumqhdov4r"
path="res://.godot/imported/hover_detector.svg-3bfd5bde28e59dd82344da683ff70f2d.ctex"
path="res://.godot/imported/cursor_detector.svg-15ede4c1c6083de1d2f8a8ceb4ab532a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/hover_detector.svg"
dest_files=["res://.godot/imported/hover_detector.svg-3bfd5bde28e59dd82344da683ff70f2d.ctex"]
source_file="res://behaviours/cursor_detector.svg"
dest_files=["res://.godot/imported/cursor_detector.svg-15ede4c1c6083de1d2f8a8ceb4ab532a.ctex"]
[params]

View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://cbg5kgwxusvxf"]
[ext_resource type="Script" path="res://behaviours/cursor_detector.gd" id="1_4hcxj"]
[node name="CursorDetector" type="Area2D"]
collision_layer = 0
collision_mask = 64
input_pickable = false
monitorable = false
script = ExtResource("1_4hcxj")
[connection signal="area_entered" from="." to="." method="_on_area_entered"]
[connection signal="area_exited" from="." to="." method="_on_area_exited"]

View file

@ -1,34 +1,19 @@
@icon("res://behaviours/draggable.svg")
extends Area2D
class_name Draggable
signal move(movement: Vector2)
signal dragged
signal dragged(cursor: Cursor)
signal dropped
@onready var mover: Node2D = $"MatchMousePosition"
var being_dragged: bool:
get:
return being_dragged
set(value):
being_dragged = value
mover.set_process(being_dragged)
mover.set_physics_process(being_dragged)
var being_dragged: bool = false
func drag():
func drag(cursor: Cursor):
being_dragged = true
dragged.emit()
dragged.emit(cursor)
func drop():
being_dragged = false
dropped.emit()
func _ready():
being_dragged = false
func _on_move(movement: Vector2):
move.emit(movement)

39
behaviours/draggable.svg Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="draggable.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
width="16"
height="16"
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">
<defs
id="defs1" />
<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:zoom="1.6464844"
inkscape:cx="217.1293"
inkscape:cy="209.84104"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="3200"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 278.6,9.4 c -12.5,-12.5 -32.8,-12.5 -45.3,0 l -64,64 c -12.5,12.5 -12.5,32.8 0,45.3 12.5,12.5 32.8,12.5 45.3,0 l 9.4,-9.4 V 224 H 109.3 l 9.4,-9.4 c 12.5,-12.5 12.5,-32.8 0,-45.3 -12.5,-12.5 -32.8,-12.5 -45.3,0 l -64,64 c -12.5,12.5 -12.5,32.8 0,45.3 l 64,64 c 12.5,12.5 32.8,12.5 45.3,0 12.5,-12.5 12.5,-32.8 0,-45.3 l -9.4,-9.4 H 224 v 114.8 l -9.4,-9.4 c -12.5,-12.5 -32.8,-12.5 -45.3,0 -12.5,12.5 -12.5,32.8 0,45.3 l 64,64 c 12.5,12.5 32.8,12.5 45.3,0 l 64,-64 c 12.5,-12.5 12.5,-32.8 0,-45.3 -12.5,-12.5 -32.8,-12.5 -45.3,0 l -9.4,9.4 V 288 h 114.8 l -9.4,9.4 c -12.5,12.5 -12.5,32.8 0,45.3 12.5,12.5 32.8,12.5 45.3,0 l 64,-64 c 12.5,-12.5 12.5,-32.8 0,-45.3 l -64,-64 c -12.5,-12.5 -32.8,-12.5 -45.3,0 -12.5,12.5 -12.5,32.8 0,45.3 l 9.4,9.4 H 288 V 109.3 l 9.4,9.4 c 12.5,12.5 32.8,12.5 45.3,0 12.5,-12.5 12.5,-32.8 0,-45.3 l -64,-64 z"
id="path1"
style="fill:#8da5f3" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -2,16 +2,16 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://8443tt517pkv"
path="res://.godot/imported/edible_tracker.svg-9169f9c07be35f707b3c167799ba3a76.ctex"
uid="uid://bepjyaq1y3g7w"
path="res://.godot/imported/draggable.svg-7f8260afa88b76990683b55fd9af07eb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/edible_tracker.svg"
dest_files=["res://.godot/imported/edible_tracker.svg-9169f9c07be35f707b3c167799ba3a76.ctex"]
source_file="res://behaviours/draggable.svg"
dest_files=["res://.godot/imported/draggable.svg-7f8260afa88b76990683b55fd9af07eb.ctex"]
[params]

View file

@ -1,15 +1,10 @@
[gd_scene load_steps=3 format=3 uid="uid://dijcjahkddudv"]
[gd_scene load_steps=2 format=3 uid="uid://dijcjahkddudv"]
[ext_resource type="Script" path="res://behaviours/draggable.gd" id="1_hdedq"]
[ext_resource type="PackedScene" uid="uid://bvrxvrjlo5130" path="res://behaviours/move_towards_mouse.tscn" id="2_gi6xd"]
[node name="Draggable" type="Area2D"]
collision_layer = 0
collision_layer = 8
collision_mask = 0
input_pickable = false
monitoring = false
script = ExtResource("1_hdedq")
[node name="MatchMousePosition" parent="." instance=ExtResource("2_gi6xd")]
scale = Vector2(10000, 10000)
speed = 3600.0
[connection signal="move" from="MatchMousePosition" to="." method="_on_move"]

View file

@ -1,37 +0,0 @@
extends Node2D
class_name EatTarget
signal eaten(target: Node2D)
signal move(movement: Vector2)
@export var tag: StringName:
get:
return tag
set(value):
tag = value
if hunt_target != null:
hunt_target.tag = value
if eater != null:
eater.tag = value
@onready var hunt_target: HuntTarget = $"HuntTarget"
@onready var eater: Eater = $"Eater"
@onready var move_towards: MoveTowardsTarget = $"MoveTowardsTarget"
func _ready():
hunt_target.tag = tag
eater.tag = tag
func _on_target_selected(body: Node2D) -> void:
move_towards.target = body
func _on_target_abandoned(_body: Node2D) -> void:
move_towards.target = null
func _on_eater_eaten(edible):
eaten.emit(edible)
func _on_move_towards_target_move(movement):
move.emit(movement)

View file

@ -1,23 +0,0 @@
[gd_scene load_steps=5 format=3 uid="uid://b7bdlh5akhi8s"]
[ext_resource type="Script" path="res://behaviours/eat_target.gd" id="1_tlnlt"]
[ext_resource type="PackedScene" uid="uid://dxmodn8mbvw0i" path="res://behaviours/hunt_target.tscn" id="2_c8wdv"]
[ext_resource type="PackedScene" uid="uid://jg7qkbswgqjc" path="res://behaviours/eater.tscn" id="3_ir2yh"]
[ext_resource type="PackedScene" uid="uid://kceb2v2dm0qn" path="res://behaviours/move_towards_target.tscn" id="4_1qc2q"]
[node name="EatTarget" type="Node2D"]
script = ExtResource("1_tlnlt")
[node name="HuntTarget" parent="." instance=ExtResource("2_c8wdv")]
scale = Vector2(16, 16)
give_up_secs = 5.0
[node name="Eater" parent="." instance=ExtResource("3_ir2yh")]
scale = Vector2(2.5, 2.5)
[node name="MoveTowardsTarget" parent="." instance=ExtResource("4_1qc2q")]
[connection signal="target_abandoned" from="HuntTarget" to="." method="_on_target_abandoned"]
[connection signal="target_selected" from="HuntTarget" to="." method="_on_target_selected"]
[connection signal="eaten" from="Eater" to="." method="_on_eater_eaten"]
[connection signal="move" from="MoveTowardsTarget" to="." method="_on_move_towards_target_move"]

View file

@ -11,6 +11,9 @@ signal eaten(edible: Edible)
@export var acceptable_diets: Array[StringName] = []
func log_eaten(edible: Edible) -> void:
Log.p(self, "Eaten: %s" % edible)
func _on_body_entered(body: Node2D) -> void:
var edibles: Array = body.find_children("Edible", "Edible", false, false)
@ -18,7 +21,3 @@ func _on_body_entered(body: Node2D) -> void:
if edible.diet in acceptable_diets:
eaten.emit(edible)
edible.eat()
func _on_eaten(edible: Edible) -> void:
Log.p(self, "Eaten: %s" % edible)

View file

@ -5,8 +5,8 @@
[node name="Eater" type="Area2D"]
collision_layer = 0
collision_mask = 8
input_pickable = false
monitorable = false
script = ExtResource("1_urx5y")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
[connection signal="eaten" from="." to="." method="_on_eaten"]

View file

@ -14,6 +14,3 @@ signal eaten
func eat():
eaten.emit()
func _on_eaten() -> void:
Log.p(self, "Got eaten.")

View file

@ -4,5 +4,3 @@
[node name="Edible" type="Node"]
script = ExtResource("1_l6vtr")
[connection signal="eaten" from="." to="." method="_on_eaten"]

View file

@ -1,34 +0,0 @@
@icon("res://behaviours/edible_tracker.svg")
extends Area2D
class_name EdibleTracker
## Keeps track of what [Edible]s are inside the area.
signal tracked(body: Node2D)
signal untracked(body: Node2D)
@export var acceptable_diets: Array[StringName] = []
var tracking: Array = []
func _on_body_entered(body: Node2D) -> void:
var edibles: Array = body.find_children("Edible", "Edible", false, false)
for edible in edibles:
if edible.tag in acceptable_diets:
tracking.push_back(body)
tracked.emit(body)
func _on_body_exited(body: Node2D) -> void:
if body in tracking:
tracking.erase(body)
untracked.emit(body)
func _on_tracked(body: Node2D) -> void:
Log.p(self, "Tracking a new target: %s" % body)
func _on_untracked(body:Node2D) -> void:
Log.p(self, "Not tracking anymore target: %s" % body)

View file

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="bowl-rice.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
width="16"
height="16"
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">
<defs
id="defs1" />
<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:zoom="1.6464844"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="1280"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 176,56 c 0,-13.3 10.7,-24 24,-24 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 H 200 C 186.7,80 176,69.3 176,56 Z m 24,48 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 z M 56,176 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 H 56 C 42.7,224 32,213.3 32,200 32,186.7 42.7,176 56,176 Z M 0,283.4 C 0,268.3 12.3,256 27.4,256 h 457.2 c 15.1,0 27.4,12.3 27.4,27.4 0,70.5 -44.4,130.7 -106.7,154.1 l -1.8,14.5 c -2,16 -15.6,28 -31.8,28 H 140.2 c -16.1,0 -29.8,-12 -31.8,-28 l -1.8,-14.4 C 44.4,414.1 0,353.9 0,283.4 Z M 224,200 c 0,-13.3 10.7,-24 24,-24 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 z m -96,0 c 0,-13.3 10.7,-24 24,-24 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 z m -24,-96 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 z m 216,96 c 0,-13.3 10.7,-24 24,-24 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 z m -24,-96 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 z m 120,96 c 0,-13.3 10.7,-24 24,-24 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 z m -24,-96 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 z M 296,32 h 16 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -16 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 z"
id="path1"
style="fill:#8da5f3" />
</svg>

Before

Width:  |  Height:  |  Size: 2.8 KiB

View file

@ -1,11 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://ctpn4hvkhxoi3"]
[ext_resource type="Script" path="res://behaviours/edible_tracker.gd" id="1_vo18u"]
[node name="EdibleTracker" type="Area2D"]
script = ExtResource("1_vo18u")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]
[connection signal="body_exited" from="." to="." method="_on_body_exited"]
[connection signal="tracked" from="." to="." method="_on_tracked"]
[connection signal="untracked" from="." to="." method="_on_untracked"]

View file

@ -1,13 +0,0 @@
@icon("res://behaviours/hover_detector.svg")
extends Area2D
class_name HoverDetector
var mouse_inside = false
func _on_mouse_entered() -> void:
mouse_inside = true
func _on_mouse_exited() -> void:
mouse_inside = false

View file

@ -1,11 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://cbg5kgwxusvxf"]
[ext_resource type="Script" path="res://behaviours/hover_detector.gd" id="1_51m5p"]
[node name="HoverDetector" type="Area2D"]
collision_mask = 0
monitorable = false
script = ExtResource("1_51m5p")
[connection signal="mouse_entered" from="." to="." method="_on_mouse_entered"]
[connection signal="mouse_exited" from="." to="." method="_on_mouse_exited"]

View file

@ -1,55 +0,0 @@
extends Node2D
class_name HuntTarget
signal target_selected(target: Node2D)
signal target_abandoned(target: Node2D)
@export var tag: StringName:
get:
return tag
set(value):
tag = value
if hunter != null:
hunter.tag = value
@export var give_up_secs: float = 5.0
@onready var give_up_timer: Timer = $"GiveUpTimer"
@onready var hunter: Hunter = $"Hunter"
var target: Node2D = null
func pick_new_target():
if hunter.possible_targets.is_empty():
return
var idx = Random.rng.randi_range(0, len(hunter.possible_targets) - 1)
target = hunter.possible_targets[idx]
target_selected.emit(target)
give_up_timer.start(give_up_secs)
func _ready():
hunter.tag = tag
func _on_hunter_tracked(_body: Node2D):
if target == null:
pick_new_target()
func _on_hunter_untracked(body: Node2D):
if body == target:
target = null
target_abandoned.emit(body)
pick_new_target()
func _on_give_up_timer_timeout() -> void:
target = null
pick_new_target()
func _on_target_selected(body: Node2D) -> void:
Log.p(self, "Target selected: %s" % body)
func _on_target_abandoned(body: Node2D) -> void:
Log.p(self, "Target abandoned: %s" % body)

View file

@ -1,18 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://dxmodn8mbvw0i"]
[ext_resource type="Script" path="res://behaviours/hunt_target.gd" id="1_1ex7u"]
[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/edible_tracker.tscn" id="2_vjdtc"]
[node name="HuntTarget" type="Node2D"]
script = ExtResource("1_1ex7u")
give_up_secs = null
[node name="Hunter" parent="." instance=ExtResource("2_vjdtc")]
[node name="GiveUpTimer" type="Timer" parent="."]
[connection signal="target_abandoned" from="." to="." method="_on_target_abandoned"]
[connection signal="target_selected" from="." to="." method="_on_target_selected"]
[connection signal="tracked" from="Hunter" to="." method="_on_hunter_tracked"]
[connection signal="untracked" from="Hunter" to="." method="_on_hunter_untracked"]
[connection signal="timeout" from="GiveUpTimer" to="." method="_on_give_up_timer_timeout"]

22
behaviours/move.gd Normal file
View file

@ -0,0 +1,22 @@
@icon("res://behaviours/move.svg")
extends Node2D
class_name Move
signal move(norm: Vector2)
signal move_toggled(value: bool)
signal move_enabled
signal move_disabled
## Whether this component should emit [signal move].
@export var enabled: bool = true:
get:
return enabled
set(value):
if enabled != value:
enabled = value
move_toggled.emit(value)
if value:
move_enabled.emit()
else:
move_disabled.emit()

39
behaviours/move.svg Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="move_towards.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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">
<defs
id="defs1" />
<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:zoom="1.6464844"
inkscape:cx="223.8102"
inkscape:cy="236.56465"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="1280"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 470.6125,278.6 c 12.5,-12.5 12.5,-32.8 0,-45.3 l -160,-160 c -12.5,-12.5 -32.8,-12.5 -45.3,0 -12.5,12.5 -12.5,32.8 0,45.3 l 105.5,105.4 h -306.8 c -17.7,0 -32,14.3 -32,32 0,17.7 14.3,32 32,32 h 306.7 l -105.3,105.4 c -12.5,12.5 -12.5,32.8 0,45.3 12.5,12.5 32.8,12.5 45.3,0 l 160,-160 z"
id="path1"
style="fill:#8da5f3" />
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d10wobjiuh1mm"
path="res://.godot/imported/move.svg-6291495a0c7bf9c3c43cbea535114f1a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/move.svg"
dest_files=["res://.godot/imported/move.svg-6291495a0c7bf9c3c43cbea535114f1a.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=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,46 @@
extends Move
class_name MovePhysics
signal dragged(cursor: Cursor)
signal dropped
signal fallen
@export var acceleration = 1250.0
@export var drag_damp = 0.4
@export var drop_damp = 0.05
@export var drop_epsilon = 16.0
var cursor: Cursor = null
var falling: bool = false
var velocity := Vector2.ZERO
func drag(value: Cursor) -> void:
cursor = value
dragged.emit(value)
func drop() -> void:
cursor = null
falling = true
dropped.emit()
func fall() -> void:
velocity = Vector2.ZERO
falling = false
fallen.emit()
func _physics_process(delta: float) -> void:
if enabled:
if cursor:
var gap = cursor.global_position - global_position
velocity += gap * delta * acceleration
velocity *= 1.0 - drag_damp
else:
velocity *= 1.0 - drop_damp
if falling and velocity.length() < drop_epsilon:
fall()
move.emit(velocity * delta)

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://rx24bppccih7"]
[ext_resource type="Script" path="res://behaviours/move_physics.gd" id="1_u02i3"]
[node name="MoveTowardsPhysics" type="Node2D"]
script = ExtResource("1_u02i3")

View file

@ -0,0 +1,35 @@
extends Move
class_name MoveStraight
## A [Move] that moves in a fixed direction.
signal changed_direction(new: Vector2)
@export var speed: float = 100.0
@export var direction: Vector2:
get:
return direction
set(value):
direction = value
changed_direction.emit(direction)
func set_direction(value: Vector2) -> void:
direction = value
func clear_direction() -> void:
direction = Vector2.ZERO
func randomize_direction() -> void:
direction = Vector2.from_angle(Random.rng.randf_range(0, 2*PI))
func log_state() -> void:
Log.p(self, "Direction: %s | Speed: %s" % [direction, speed])
func _physics_process(delta: float) -> void:
if enabled:
move.emit(direction * delta * speed)

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dk1ipq7dhkhf3"]
[ext_resource type="Script" path="res://behaviours/move_straight.gd" id="1_8yf73"]
[node name="MoveStraight" type="Node2D"]
script = ExtResource("1_8yf73")

View file

@ -1,44 +1,38 @@
extends Node2D
extends Move
class_name MoveTowards
signal move(movement: Vector2)
signal detached
signal captured
## A [Move] that moves towards the [field position] of a [field target].
signal changed_target(new: Node2D)
@export var speed: float = 100.0
@export var can_detach: bool = false
@export var target: Node2D = null:
get:
return target
set(value):
target = value
changed_target.emit(value)
enum State { DETACHED, CAPTURED }
func set_target(value: Node2D) -> void:
target = value
var state: State = State.DETACHED
func clear_target() -> void:
target = null
func get_followed_global_position():
return Vector2.ZERO # OVERRIDE ME!
func get_followed_mouse_position():
var global_followed_position: Vector2 = get_followed_global_position()
var relative_followed_position: Vector2 = global_followed_position - global_position
return relative_followed_position
func log_target() -> void:
Log.p(self, "Target: %s" % target)
func _physics_process(delta: float) -> void:
match state:
State.CAPTURED:
var relative_followed_position: Vector2 = get_followed_mouse_position()
var direction: Vector2 = position.direction_to(relative_followed_position)
var actual_speed: float = min(delta * speed, relative_followed_position.length()) # Don't overshoot.
var movement: Vector2 = direction * actual_speed
move.emit(movement)
func _on_capture_area_mouse_entered() -> void:
state = State.CAPTURED
captured.emit()
func _on_capture_area_mouse_exited() -> void:
if can_detach:
state = State.DETACHED
detached.emit()
if enabled:
if target:
var gap = target.global_position - global_position
var norm = gap.normalized()
move.emit(norm * delta * speed)
else:
move.emit(Vector2.ZERO)

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://cml7rqvyfuagx"]
[ext_resource type="Script" path="res://behaviours/move_towards.gd" id="1_256ue"]
[node name="MoveTowards" type="Node2D"]
script = ExtResource("1_256ue")

View file

@ -1,46 +0,0 @@
extends Node2D
class_name MoveTowardsMouse
signal move(movement: Vector2)
signal detached
signal captured
@onready var game := MainGame.get_ancestor(self)
@export var speed: float = 100.0
@export var can_detach: bool = false
enum State { DETACHED, CAPTURED }
var state: State = State.DETACHED
func get_followed_global_position():
return game.camera.get_global_mouse_position()
func get_followed_mouse_position():
var global_followed_position: Vector2 = get_followed_global_position()
var relative_followed_position: Vector2 = global_followed_position - global_position
return relative_followed_position
func _physics_process(delta: float) -> void:
match state:
State.CAPTURED:
var relative_followed_position: Vector2 = get_followed_mouse_position()
var direction: Vector2 = position.direction_to(relative_followed_position)
var actual_speed: float = min(delta * speed, relative_followed_position.length()) # Don't overshoot.
var movement: Vector2 = direction * actual_speed
move.emit(movement)
func _on_capture_area_mouse_entered() -> void:
state = State.CAPTURED
captured.emit()
func _on_capture_area_mouse_exited() -> void:
if can_detach:
state = State.DETACHED
detached.emit()

View file

@ -1,12 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://bvrxvrjlo5130"]
[ext_resource type="Script" path="res://behaviours/move_towards_mouse.gd" id="1_nbja1"]
[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/hover_detector.tscn" id="2_qru2e"]
[node name="MoveTowardsMouse" type="Node2D"]
script = ExtResource("1_nbja1")
[node name="CaptureArea" parent="." instance=ExtResource("2_qru2e")]
[connection signal="mouse_entered" from="CaptureArea" to="." method="_on_capture_area_mouse_entered"]
[connection signal="mouse_exited" from="CaptureArea" to="." method="_on_capture_area_mouse_exited"]

View file

@ -1,29 +0,0 @@
extends Node2D
class_name MoveTowardsTarget
signal move(movement: Vector2)
@export var speed: float = 100.0
@export var target: Node2D
func get_followed_global_position():
return target.global_position
func get_followed_mouse_position():
var global_followed_position: Vector2 = get_followed_global_position()
var relative_followed_position: Vector2 = global_followed_position - global_position
return relative_followed_position
func _physics_process(delta: float) -> void:
if target == null:
return
var relative_followed_position: Vector2 = get_followed_mouse_position()
var direction: Vector2 = position.direction_to(relative_followed_position)
var actual_speed: float = min(delta * speed, relative_followed_position.length()) # Don't overshoot.
var movement: Vector2 = direction * actual_speed
move.emit(movement)

View file

@ -1,6 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://kceb2v2dm0qn"]
[ext_resource type="Script" path="res://behaviours/move_towards_target.gd" id="1_703gy"]
[node name="MoveTowardsTarget" type="Node2D"]
script = ExtResource("1_703gy")

69
behaviours/priority.gd Normal file
View file

@ -0,0 +1,69 @@
@icon("res://behaviours/priority.svg")
extends Node
class_name Priority
## Keeps track of the object's priority for [SamplerPriority] purposes.
## Emitted when the priority is changed.
signal priority_changed(new: int, old: int)
## Emitted when the priority is changed. No args are provided to work around a Godot bug.
signal priority_changed_no_args
@export var default_priority: int = 0
@export var alternative_priority: int = 1
var priority: int = 0:
get:
return priority
set(value):
var old = priority
priority = value
priority_changed.emit(priority, old)
## Set [field priority] to [field default_priority].
func priority_default() -> void:
priority = default_priority
## Set [field priority] to [field alternative_priority]
func priority_alternative() -> void:
priority = alternative_priority
## Toggle [field priority] between [field default_priority] and [field alternative_priority].
func priority_toggle() -> void:
if priority == default_priority:
priority = alternative_priority
else:
priority = default_priority
## Set the [field priority] to a specific value.
func priority_set(value: int):
priority = value
## Set the [field priority] to a specific value if the [param variant] is truthy, otherwise set it to a different value.
##
## Defaults to using [field alternative_priority] for truthy, and [field default_priority] for falsy
func priority_conditional(variant: Variant, truthy: int = alternative_priority, falsy: int = default_priority):
if variant:
priority = truthy
else:
priority = falsy
## Get the node to which the [field priority] of this one applies to.
func get_ref() -> Node:
return get_parent()
## Log the current [field priority] value.
func log_priority() -> void:
Log.p(self, "Priority: %d" % priority)
func _on_priority_changed(_new: int, _old: int) -> void:
priority_changed_no_args.emit()
func _ready() -> void:
priority = default_priority

39
behaviours/priority.svg Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 575.99539 575.99537"
version="1.1"
id="svg1"
sodipodi:docname="priority.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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">
<defs
id="defs1" />
<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:zoom="1.6464844"
inkscape:cx="287.88612"
inkscape:cy="248.71174"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="1280"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 316.72587,49.969031 c -5.3,-11 -16.5,-18 -28.8,-18 -12.3,0 -23.4,7 -28.8,18 l -64.3,132.299999 -143.600005,21.2 c -12,1.8 -22,10.2 -25.7,21.7 -3.7,11.5 -0.7,24.2 7.9,32.7 l 104.200005,103.1 -24.6,145.7 c -2,12 3,24.2 12.9,31.3 9.9,7.1 23,8 33.8,2.3 l 128.3,-68.5 128.3,68.5 c 10.8,5.7 23.9,4.9 33.8,-2.3 9.9,-7.2 14.9,-19.3 12.9,-31.3 l -24.7,-145.7 104.2,-103.1 c 8.6,-8.5 11.7,-21.2 7.9,-32.7 -3.8,-11.5 -13.7,-19.9 -25.7,-21.7 l -143.7,-21.2 z"
id="path1"
style="fill:#e0e0e0" />
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ctc4lx571jksr"
path="res://.godot/imported/priority.svg-d16c10b6303969bc43c2b8feaccb77ae.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/priority.svg"
dest_files=["res://.godot/imported/priority.svg-d16c10b6303969bc43c2b8feaccb77ae.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=false
editor/convert_colors_with_editor_theme=false

8
behaviours/priority.tscn Normal file
View file

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://cm67ko1k6kn4u"]
[ext_resource type="Script" path="res://behaviours/priority.gd" id="1_8u7ji"]
[node name="Priority" type="Node"]
script = ExtResource("1_8u7ji")
[connection signal="priority_changed" from="." to="." method="_on_priority_changed"]

29
behaviours/sampler.gd Normal file
View file

@ -0,0 +1,29 @@
@icon("res://behaviours/sampler.svg")
extends Node
class_name Sampler
## Abstract base class for sampling a certain reference among multiple.
## [Array] of [Node]s that can be [func sample]d by this [Sampler].
@export var possibilities: Array[Node] = []
## Get a reference.
func sample() -> Node:
Log.e(self, "Not implemented.")
return null
## Set the [field enabled] property to true on a [method sample]d node, and to false on all others.
func enable() -> void:
var selected = sample()
for possibility in get_all_refs():
possibility.enabled = (selected == possibility)
## Get all possible nodes referenced by [field possibilities].
##
## Useful as it may be overridden by some other [Sampler]s, such as [SamplerPriority].
func get_all_refs() -> Array[Node]:
return possibilities

59
behaviours/sampler.svg Normal file
View file

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="sampler.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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">
<defs
id="defs1" />
<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:zoom="13.171875"
inkscape:cx="16.778173"
inkscape:cy="17.651246"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="3200"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 48,368 a 48,48 0 1 1 0,96 48,48 0 1 1 0,-96 z"
id="path6"
style="fill:#e0e0e0" />
<path
d="m 160,416 c 0,-17.7 14.3,-32 32,-32 h 288 c 17.7,0 32,14.3 32,32 0,17.7 -14.3,32 -32,32 H 192 c -17.7,0 -32,-14.3 -32,-32 z"
id="path5"
style="fill:#e0e0e0" />
<path
d="m 160,256 c 0,-17.7 14.3,-32 32,-32 h 288 c 17.7,0 32,14.3 32,32 0,17.7 -14.3,32 -32,32 H 192 c -17.7,0 -32,-14.3 -32,-32 z"
id="path5-7"
style="fill:#e0e0e0" />
<path
d="m 224,96 c 0,-17.7 14.3,-32 32,-32 h 224 c 17.7,0 32,14.3 32,32 0,17.7 -14.3,32 -32,32 H 256 c -17.7,0 -32,-14.3 -32,-32 z"
id="path3"
style="fill:#e0e0e0" />
<path
d="m 152.1,38.2 c 9.9,8.9 10.7,24 1.8,33.9 l -72,80 c -4.4,4.9 -10.6,7.8 -17.2,7.9 -6.6,0.1 -12.9,-2.4 -17.6,-7 L 7,113 c -9.3,-9.4 -9.3,-24.6 0,-34 9.3,-9.4 24.6,-9.4 33.9,0 L 63,101.1 118.1,39.9 C 127,30 142.1,29.2 152,38.1 Z"
id="path1"
style="fill:#8eef97" />
<path
d="M 96,256 A 48,48 0 1 0 5e-7,256 48,48 0 1 0 96,256 Z"
id="path6-5"
style="fill:#e0e0e0" />
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cv32pf38ugoh1"
path="res://.godot/imported/sampler.svg-3634a55299eb9a683092cba4e7d215f9.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/sampler.svg"
dest_files=["res://.godot/imported/sampler.svg-3634a55299eb9a683092cba4e7d215f9.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=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,28 @@
extends Sampler
class_name SamplerPriority
## Always sample the object with the highest priority in the queue.
## Get a reference.
func sample() -> Priority:
if len(possibilities) == 0:
return null
# FIXME: Change this to something more efficient when needed
var highest_possibility: Priority = null
for possibility in possibilities:
if highest_possibility == null or possibility.priority > highest_possibility.priority:
highest_possibility = possibility
if highest_possibility == null:
return null
return highest_possibility.get_ref()
func get_all_refs() -> Array[Node]:
var refs: Array[Node] = []
for possibility in possibilities:
refs.append(possibility.get_ref())
return refs

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://djcwis8ycrq85"]
[ext_resource type="Script" path="res://behaviours/sampler_priority.gd" id="1_jy5r5"]
[node name="SamplerPriority" type="Node"]
script = ExtResource("1_jy5r5")

View file

@ -0,0 +1,11 @@
extends Sampler
class_name SamplerRandom
## Sample a random reference from the array.
func sample() -> Node:
if len(possibilities) == 0:
return null
return Random.sample(possibilities)

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dtiuw54ss376d"]
[ext_resource type="Script" path="res://behaviours/sampler_random.gd" id="1_geacn"]
[node name="SamplerRandom" type="Node"]
script = ExtResource("1_geacn")

View file

@ -1,34 +1,29 @@
extends Node
class_name SpawnerChoice
extends Sampler
class_name SamplerWeighted
## Sample a random reference from the array, considering the given weights.
@export var spawners: Array[Spawner] = []
@export var weights: Array[int] = []
func sample() -> Node:
var total = compute_total_weight()
if total == 0:
return null
var sampled = Random.rng.randi_range(0, total - 1)
var idx = -1
while sampled >= 0:
idx += 1
sampled -= weights[idx]
return possibilities[idx]
func compute_total_weight() -> int:
var total = 0
for weight in weights:
if weight < 0:
Log.e(self, "Weight with negative value detected.")
return 0
total += weight
return total
func select_spawner() -> Spawner:
var total = compute_total_weight()
var sampled = Random.rng.randi_range(0, total - 1)
var idx = -1
while sampled >= 0:
idx += 1
sampled -= weights[idx]
return spawners[idx]
func spawn():
select_spawner().spawn()
func _ready():
if len(spawners) != len(weights):
Log.e(self, "Spawners and weights are different lengths.")
if compute_total_weight() <= 0:
Log.e(self, "Weight total is less or equal to 0.")

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://d2ftjun7wdif0"]
[ext_resource type="Script" path="res://behaviours/sampler_weighted.gd" id="1_hhnbk"]
[node name="SamplerWeighted" type="Node"]
script = ExtResource("1_hhnbk")

View file

@ -1,68 +0,0 @@
extends Node2D
class_name SkitterFromMouse
signal move(movement: Vector2)
signal scared
signal calmed
@export_range(1, 500, 1) var speed: float = 300.0
@export_range(0.1, 5, 0.1) var scare_secs: float = 0.2
@export var directions: Array[Vector2] = []
@onready var calm_timer: Timer = $"CalmTimer"
@onready var scare_area: HoverDetector = $"ScareArea"
enum State { CALM, SCARED }
var state := State.CALM
var direction := Vector2.ZERO
func recheck():
if scare_area.mouse_inside:
scare()
else:
calm()
func calm():
state = State.CALM
calmed.emit()
func scare():
state = State.SCARED
# Pick a direction
var idx := Random.rng.randi_range(0, len(directions) - 1)
direction = directions[idx]
# Start the timeout for calming down
calm_timer.start(scare_secs)
scared.emit()
func _ready():
if not directions:
Log.w(self, "No directions defined, object won't skitter.")
func _physics_process(delta: float) -> void:
match state:
State.SCARED:
if len(directions) > 0:
var movement: Vector2 = direction * delta * speed
move.emit(movement)
func _on_calm_timer_timeout() -> void:
recheck()
func _on_hover_detector_mouse_entered() -> void:
scare()
func _on_move(movement: Vector2) -> void:
Log.p(self, "Moving by: %s" % movement)
func _on_scared() -> void:
Log.p(self, "Scared!")
func _on_calmed() -> void:
Log.p(self, "Calmed down.")

View file

@ -1,18 +0,0 @@
[gd_scene load_steps=3 format=3 uid="uid://c1wqgyakaultt"]
[ext_resource type="Script" path="res://behaviours/skitter_from_mouse.gd" id="1_ftcf8"]
[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/hover_detector.tscn" id="2_cuaq0"]
[node name="SkitterFromMouse" type="Node2D"]
script = ExtResource("1_ftcf8")
[node name="ScareArea" parent="." instance=ExtResource("2_cuaq0")]
[node name="CalmTimer" type="Timer" parent="."]
one_shot = true
[connection signal="calmed" from="." to="." method="_on_calmed"]
[connection signal="move" from="." to="." method="_on_move"]
[connection signal="scared" from="." to="." method="_on_scared"]
[connection signal="mouse_entered" from="ScareArea" to="." method="_on_hover_detector_mouse_entered"]
[connection signal="timeout" from="CalmTimer" to="." method="_on_calm_timer_timeout"]

View file

@ -1,19 +1,37 @@
@icon("res://behaviours/spawner.svg")
extends Node2D
class_name Spawner
## Emitted when a new scene is spawned.
signal spawned(entity: Node2D)
@export var scene: PackedScene
@export var parent: Node2D
## Emitted when the [field blocking_tracker] prevents something from spawning.
signal spawn_blocked
## The scene to spawn.
@export var scene: PackedScene
## Where the scene should be parented to in the tree.
@export var target: Node2D
## If set, requires the tracker to not be tracking anything before spawning a scene.
@export var blocking_tracker: Tracker
## Spawn [field scene] at [field target] and the position of this node.
func spawn():
if blocking_tracker != null:
if not blocking_tracker.tracking.is_empty():
spawn_blocked.emit()
return # Perhaps enqueue the spawn?
if not target:
target = MainGame.get_via_group(self).default_spawn_parent
if not target:
target = self
var entity = scene.instantiate()
entity.global_scale = global_scale
entity.global_position = global_position
entity.global_rotation = global_rotation
parent.add_child.call_deferred(entity) # Not sure why this is needed.
func _ready():
if parent == null:
parent = MainGame.get_ancestor(self).get_node("SpawnedEntities")
target.add_child.call_deferred(entity) # Not sure why this is needed.

47
behaviours/spawner.svg Normal file
View file

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 640 640"
version="1.1"
id="svg1"
sodipodi:docname="spawner.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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">
<defs
id="defs1" />
<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:zoom="26.34375"
inkscape:cx="13.001186"
inkscape:cy="9.9264532"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="1280"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 504,376 v -64 h -64 c -13.3,0 -24,-10.7 -24,-24 0,-13.3 10.7,-24 24,-24 h 64 v -64 c 0,-13.3 10.7,-24 24,-24 13.3,0 24,10.7 24,24 v 64 h 64 c 13.3,0 24,10.7 24,24 0,13.3 -10.7,24 -24,24 h -64 v 64 c 0,13.3 -10.7,24 -24,24 -13.3,0 -24,-10.7 -24,-24 z"
id="path3"
style="fill:#73f280;fill-opacity:1" />
<path
d="M 0,546.3 C 0,447.8 79.8,368 178.3,368 h 91.4 c 98.5,0 178.3,79.8 178.3,178.3 0,16.4 -13.3,29.7 -29.7,29.7 H 29.7 C 13.3,576 0,562.7 0,546.3 Z"
id="path2"
style="fill:#8da5f3" />
<path
d="m 96,192 a 128,128 0 1 1 256,0 128,128 0 1 1 -256,0 z"
id="path1"
style="fill:#8da5f3" />
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://2okawpk7lh5j"
path="res://.godot/imported/spawner.svg-02e649ce51fee431d04ebb532f1c81e8.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/spawner.svg"
dest_files=["res://.godot/imported/spawner.svg-02e649ce51fee431d04ebb532f1c81e8.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=false
editor/convert_colors_with_editor_theme=false

View file

@ -1,6 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://cokdfsk6rgeup"]
[ext_resource type="Script" path="res://behaviours/spawner_choice.gd" id="1_jkwdb"]
[node name="SpawnerChoice" type="Node"]
script = ExtResource("1_jkwdb")

View file

@ -1,8 +0,0 @@
[gd_scene load_steps=2 format=3 uid="uid://dv7ea2y0l46e"]
[ext_resource type="Script" path="res://behaviours/spawner.gd" id="1_fa574"]
[node name="SpawnerFree" type="Node2D"]
script = ExtResource("1_fa574")
[connection signal="tree_exiting" from="." to="." method="spawn"]

View file

@ -0,0 +1,48 @@
@icon("res://behaviours/target_picker.svg")
extends Node
class_name TargetPicker
## Pick a random target at random from [field Tracker.tracked], then emit it via [signal target_changed].
signal target_changed(new: Node2D, old: Node2D)
@export var tracker: Tracker
var target: Node2D:
get:
return target
set(value):
if target != value:
var old = target
target = value
target_changed.emit(target, old)
func set_target(body: Node2D) -> void:
target = body
func set_target_if_null(body: Node2D) -> void:
if target == null:
target = body
func clear_target() -> void:
target = null
func clear_if_target(body: Node2D) -> void:
if target == body:
clear_target()
func sample_target() -> void:
target = Random.sample(tracker.tracking)
func sample_target_if_null() -> void:
if target == null:
sample_target()
func log_target() -> void:
pass # Replace with function body.

View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="target_picker_random.svg"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
width="16"
height="16"
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">
<defs
id="defs1" />
<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:zoom="1.6464844"
inkscape:cx="256"
inkscape:cy="256"
inkscape:window-width="1920"
inkscape:window-height="1020"
inkscape:window-x="3200"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 448,256 a 192,192 0 1 0 -384,0 192,192 0 1 0 384,0 z M 0,256 a 256,256 0 1 1 512,0 256,256 0 1 1 -512,0 z m 256,80 a 80,80 0 1 0 0,-160 80,80 0 1 0 0,160 z m 0,-224 a 144,144 0 1 1 0,288 144,144 0 1 1 0,-288 z m -32,144 a 32,32 0 1 1 64,0 32,32 0 1 1 -64,0 z"
id="path1"
style="fill:#e0e0e0" />
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dd7uvjl416h2k"
path="res://.godot/imported/target_picker.svg-d96365c33742930a50d2b51102fd20f0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/target_picker.svg"
dest_files=["res://.godot/imported/target_picker.svg-d96365c33742930a50d2b51102fd20f0.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=false
editor/convert_colors_with_editor_theme=false

View file

@ -0,0 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://dti7l0d40hhgt"]
[ext_resource type="Script" path="res://behaviours/target_picker.gd" id="1_ldiw7"]
[node name="TargetPicker" type="Node"]
script = ExtResource("1_ldiw7")

View file

@ -0,0 +1,19 @@
extends Timer
class_name TimerStddev
## A [Timer] which randomizes its [field wait_time] at each timeout.
@export_range(0, 10, 0.1, "or_greater") var mean_secs: float = 1.0
@export var deviation: float = 1.0
@export_range(0, 10, 0.1, "or_greater") var min_secs: float = 0.0
@export_range(0, 10, 0.1, "or_greater") var max_secs: float = 2.0
func randomize_wait_time() -> void:
wait_time = clampf(
min_secs,
Random.rng.randfn(mean_secs, deviation),
max_secs
)

View file

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://g8t6dt0ye6n3"]
[ext_resource type="Script" path="res://behaviours/timer_stddev.gd" id="1_rvemn"]
[node name="TimerStddev" type="Timer"]
script = ExtResource("1_rvemn")
[connection signal="timeout" from="." to="." method="randomize_wait_time"]

44
behaviours/tracker.gd Normal file
View file

@ -0,0 +1,44 @@
@icon("res://behaviours/tracker.svg")
extends Area2D
class_name Tracker
## [Area2D]s tracking a certain subset of [Node2D]s.
signal tracked(body: Node2D)
signal untracked(body: Node2D)
var tracking: Array = []
## Start [field tracking] a [Node2D].
##
## Returns whether the body was added to the [field tracking] array.
func track(body: Node2D) -> bool:
var act: bool = not body in tracking
if act:
tracking.push_back(body)
tracked.emit(body)
# Handle TrackerTracker
for tracker_tracker in body.find_children("*", "TrackerTracker", true, false):
tracker_tracker.track_if_detected(self)
return act
## Stop [field tracking] a [Node2D].
##
## Returns whether the body was removed from the [field tracking] array.
func untrack(body: Node2D) -> bool:
var act: bool = body in tracking
if act:
tracking.erase(body)
untracked.emit(body)
# Handle TrackerTracker
for tracker_tracker in body.find_children("*", "TrackerTracker", true, false):
tracker_tracker.untrack(self)
return act
func log_tracked(body: Node2D) -> void:
Log.p(self, "Tracking a new target: %s" % body)
func log_untracked(body: Node2D) -> void:
Log.p(self, "Not tracking anymore target: %s" % body)

39
behaviours/tracker.svg Normal file
View file

@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
viewBox="0 0 512 512"
version="1.1"
id="svg1"
sodipodi:docname="tracker.svg"
width="16"
height="16"
inkscape:version="1.3.2 (091e20ef0f, 2023-11-25, custom)"
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">
<defs
id="defs1" />
<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:zoom="8"
inkscape:cx="21.0625"
inkscape:cy="41.9375"
inkscape:window-width="1280"
inkscape:window-height="964"
inkscape:window-x="0"
inkscape:window-y="60"
inkscape:window-maximized="1"
inkscape:current-layer="svg1" />
<!--! Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2024 Fonticons, Inc. -->
<path
d="m 256,0 c 17.7,0 32,14.3 32,32 v 10.4 c 93.7,13.9 167.7,88 181.6,181.6 H 480 c 17.7,0 32,14.3 32,32 0,17.7 -14.3,32 -32,32 H 469.6 C 455.7,381.7 381.6,455.7 288,469.6 V 480 c 0,17.7 -14.3,32 -32,32 -17.7,0 -32,-14.3 -32,-32 V 469.6 C 130.3,455.7 56.3,381.7 42.4,288 H 32 C 14.3,288 0,273.7 0,256 0,238.3 14.3,224 32,224 H 42.4 C 56.3,130.3 130.3,56.3 224,42.4 V 32 C 224,14.3 238.3,0 256,0 Z M 107.4,288 c 12.5,58.3 58.4,104.1 116.6,116.6 V 384 c 0,-17.7 14.3,-32 32,-32 17.7,0 32,14.3 32,32 v 20.6 C 346.3,392.1 392.1,346.2 404.6,288 H 384 c -17.7,0 -32,-14.3 -32,-32 0,-17.7 14.3,-32 32,-32 h 20.6 C 392.1,165.7 346.3,119.9 288,107.4 V 128 c 0,17.7 -14.3,32 -32,32 -17.7,0 -32,-14.3 -32,-32 V 107.4 C 165.7,119.9 119.9,165.7 107.4,224 H 128 c 17.7,0 32,14.3 32,32 0,17.7 -14.3,32 -32,32 z M 256,224 a 32,32 0 1 1 0,64 32,32 0 1 1 0,-64 z"
id="path1"
style="fill:#699ce8" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

View file

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://b3myvaqud7w0p"
path="res://.godot/imported/tracker.svg-98e9b55805c6d630e7da524610510efd.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://behaviours/tracker.svg"
dest_files=["res://.godot/imported/tracker.svg-98e9b55805c6d630e7da524610510efd.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=false
editor/convert_colors_with_editor_theme=false

13
behaviours/tracker.tscn Normal file
View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://8jkesanu4hrn"]
[ext_resource type="Script" path="res://behaviours/tracker.gd" id="1_4joji"]
[node name="Tracker" type="Area2D"]
collision_layer = 0
collision_mask = 56
input_pickable = false
monitorable = false
script = ExtResource("1_4joji")
[connection signal="body_entered" from="." to="." method="track"]
[connection signal="body_exited" from="." to="." method="untrack"]

View file

@ -0,0 +1,15 @@
extends Tracker
class_name EdibleTracker
## Keeps track of what [Edible]s are inside the area.
@export var acceptable_diets: Array[StringName] = []
func check_diet_then_track(body: Node2D) -> void:
var edibles: Array = body.find_children("*", "Edible", false, false)
for edible in edibles:
if edible.diet in acceptable_diets:
track(body)
break

View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://ctpn4hvkhxoi3"]
[ext_resource type="Script" path="res://behaviours/tracker_edible.gd" id="1_vmdw6"]
[node name="TrackerEdible" type="Area2D"]
collision_layer = 0
collision_mask = 56
input_pickable = false
monitorable = false
script = ExtResource("1_vmdw6")
[connection signal="body_entered" from="." to="." method="check_diet_then_track"]
[connection signal="body_exited" from="." to="." method="untrack"]

View file

@ -0,0 +1,24 @@
extends Tracker
class_name TrackerTracker
## Tracks [Tracker]s tracking the parent.
## Start [field tracking] a [Node2D] if it overlaps this [Area2D].
##
## Returns whether the body was added to the [field tracking] array.
func track_if_detected(body: Node2D) -> bool:
if overlaps_body(body):
return track(body)
return false
## Start [field tracking] a [Node2D] if it has a [Tracker] tracking this node or one of its ancestors.
##
## Returns whether the body was added to the [field tracking] array.
func track_if_tracked(body: Node2D) -> bool:
var act: bool = false
for tracker in body.find_children("*", "Tracker", true, false):
for ancestor in Traversal.get_ancestors(self): # Make more efficient, perhaps?
if ancestor in tracker.tracking:
act = track(body) or act
return act

View file

@ -0,0 +1,13 @@
[gd_scene load_steps=2 format=3 uid="uid://c5pyp5hvthdof"]
[ext_resource type="Script" path="res://behaviours/tracker_tracker.gd" id="1_7b21r"]
[node name="TrackerTracker" type="Area2D"]
collision_layer = 0
collision_mask = 24
input_pickable = false
monitorable = false
script = ExtResource("1_7b21r")
[connection signal="body_entered" from="." to="." method="track_if_tracked"]
[connection signal="body_exited" from="." to="." method="untrack"]

BIN
entities/drop.wav (Stored with Git LFS)

Binary file not shown.

View file

@ -1,24 +0,0 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://buxgivpkh8dyl"
path="res://.godot/imported/drop.wav-e321e3ff0b5883beef3e60642ca137ca.sample"
[deps]
source_file="res://entities/drop.wav"
dest_files=["res://.godot/imported/drop.wav-e321e3ff0b5883beef3e60642ca137ca.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

BIN
entities/fall.ogg (Stored with Git LFS) Normal file

Binary file not shown.

19
entities/fall.ogg.import Normal file
View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://cwsg776c11xfc"
path="res://.godot/imported/fall.ogg-ba2036bd4382e626c27cc3d1d5eb69f1.oggvorbisstr"
[deps]
source_file="res://entities/fall.ogg"
dest_files=["res://.godot/imported/fall.ogg-ba2036bd4382e626c27cc3d1d5eb69f1.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

View file

@ -2,18 +2,23 @@ extends Node2D
class_name Gold
@export var value: int = 1
@onready var game: MainGame = MainGame.get_via_group(self)
@onready var move_towards: MoveTowards = %"MoveTowards"
@onready var collect_sound_spawner: Spawner = %"CollectSoundSpawner"
@onready var collectible: Collectible = %"Collectible"
func magnetize(cursor: Cursor) -> void:
move_towards.target = cursor
func demagnetize() -> void:
move_towards.target = null
func collect() -> void:
collectible.apply()
collect_sound_spawner.spawn()
queue_free()
func _on_move(movement: Vector2) -> void:
position += movement
func _on_collected(tag: StringName) -> void:
var game = MainGame.get_ancestor(self)
# TODO: Perhaps use a dictionary in game to store multiple currencies?
match tag:
&"Gold":
game.gold_counter.increase(value)
queue_free()

View file

@ -1,29 +1,50 @@
[gd_scene load_steps=7 format=3 uid="uid://uoxwjpmgg27a"]
[gd_scene load_steps=10 format=3 uid="uid://uoxwjpmgg27a"]
[ext_resource type="Script" path="res://entities/gold.gd" id="1_lbls1"]
[ext_resource type="PackedScene" uid="uid://bvrxvrjlo5130" path="res://behaviours/move_towards_mouse.tscn" id="2_lso1v"]
[ext_resource type="PackedScene" uid="uid://dj72yshd25ucx" path="res://behaviours/collectible.tscn" id="2_j75yq"]
[ext_resource type="Texture2D" uid="uid://bfl0tkg85cvb8" path="res://entities/gold.png" id="2_tt3v6"]
[ext_resource type="PackedScene" uid="uid://dj72yshd25ucx" path="res://behaviours/collectable.tscn" id="3_q0bno"]
[ext_resource type="PackedScene" uid="uid://dv7ea2y0l46e" path="res://behaviours/spawner_free.tscn" id="5_pbaso"]
[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/cursor_detector.tscn" id="3_ne3sj"]
[ext_resource type="PackedScene" uid="uid://cml7rqvyfuagx" path="res://behaviours/move_towards.tscn" id="5_bcbgf"]
[ext_resource type="PackedScene" uid="uid://tx1qi6ahlxjp" path="res://behaviours/spawner.tscn" id="5_t7ey8"]
[ext_resource type="PackedScene" uid="uid://eqg6snsgn1kh" path="res://players/gold_pickup_player.tscn" id="6_eoeje"]
[sub_resource type="CircleShape2D" id="CircleShape2D_w1h35"]
radius = 64.0
[sub_resource type="CircleShape2D" id="CircleShape2D_jm7yp"]
[node name="Gold" type="Node2D"]
script = ExtResource("1_lbls1")
[node name="Collectible" parent="." instance=ExtResource("2_j75yq")]
unique_name_in_owner = true
kind = &"Gold"
[node name="Sprite" type="Sprite2D" parent="."]
scale = Vector2(2, 2)
texture = ExtResource("2_tt3v6")
[node name="MoveTowardsMouse" parent="." instance=ExtResource("2_lso1v")]
scale = Vector2(8, 8)
speed = 555.0
[node name="MagnetizeArea" parent="." instance=ExtResource("3_ne3sj")]
[node name="Collectable" parent="." instance=ExtResource("3_q0bno")]
scale = Vector2(0.6, 0.6)
tag = &"Gold"
[node name="Shape" type="CollisionShape2D" parent="MagnetizeArea"]
shape = SubResource("CircleShape2D_w1h35")
debug_color = Color(0.337255, 0.611765, 1, 0)
[node name="SpawnerFree" parent="." instance=ExtResource("5_pbaso")]
[node name="CollectArea" parent="." instance=ExtResource("3_ne3sj")]
[node name="Shape" type="CollisionShape2D" parent="CollectArea"]
shape = SubResource("CircleShape2D_jm7yp")
debug_color = Color(0, 0.388235, 0.815686, 0.219608)
[node name="MoveTowards" parent="." instance=ExtResource("5_bcbgf")]
unique_name_in_owner = true
speed = 184.0
[node name="CollectSoundSpawner" parent="." instance=ExtResource("5_t7ey8")]
unique_name_in_owner = true
scale = Vector2(1.66667, 1.66667)
scene = ExtResource("6_eoeje")
[connection signal="move" from="MoveTowardsMouse" to="." method="_on_move"]
[connection signal="collected" from="Collectable" to="." method="_on_collected"]
[connection signal="cursor_entered" from="MagnetizeArea" to="." method="magnetize"]
[connection signal="cursor_entered" from="CollectArea" to="." method="collect" unbinds=1]
[connection signal="move" from="MoveTowards" to="." method="_on_move"]

View file

@ -1,25 +1,26 @@
extends CharacterBody2D
class_name Imp
@export var skull_chance: float = 0.2
@onready var skull_spawner: Spawner = $"SkullSpawner"
@onready var sprite: SpriteLeftRight = $"Sprite"
@onready var draggable: Draggable = $"Draggable"
@onready var eater: Eater = $"Eater"
func _on_eat_target_eaten(target: Edible):
target.queue_free()
if Random.rng.randf() < skull_chance:
skull_spawner.spawn()
func _on_move(movement: Vector2):
move_and_collide(movement)
sprite.handle_move(movement)
func _on_eater_eaten(edible: Edible) -> void:
edible.get_parent().queue_free()
func _on_draggable_move(movement:Vector2):
if draggable.being_dragged:
move_and_collide(movement)
sprite.handle_move(movement)
func _on_dragged(_cursor: Cursor) -> void:
collision_layer = 16
collision_mask = 18
z_index = 1
eater.collision_mask = 16
func _on_move(movement:Vector2):
if not draggable.being_dragged:
move_and_collide(movement)
sprite.handle_move(movement)
func _on_fallen() -> void:
collision_layer = 8
collision_mask = 14
z_index = 0
eater.collision_mask = 8

View file

@ -1,20 +1,41 @@
[gd_scene load_steps=10 format=3 uid="uid://4d3ksr3171x4"]
[gd_scene load_steps=24 format=3 uid="uid://4d3ksr3171x4"]
[ext_resource type="Script" path="res://entities/imp.gd" id="1_dixpc"]
[ext_resource type="PackedScene" uid="uid://bxbjfev0lhwws" path="res://behaviours/sprite_left_right.tscn" id="2_eqcdi"]
[ext_resource type="PackedScene" uid="uid://dijcjahkddudv" path="res://behaviours/draggable.tscn" id="3_4528r"]
[ext_resource type="PackedScene" uid="uid://b7bdlh5akhi8s" path="res://behaviours/eat_target.tscn" id="3_iybf3"]
[ext_resource type="Texture2D" uid="uid://crhwsob76ieya" path="res://entities/imp_left.png" id="3_qda0k"]
[ext_resource type="Texture2D" uid="uid://bubehid53q8h1" path="res://entities/imp_right.png" id="4_0sckn"]
[ext_resource type="PackedScene" path="res://behaviours/spawner.tscn" id="4_d8lgm"]
[ext_resource type="PackedScene" uid="uid://tx1qi6ahlxjp" path="res://behaviours/spawner.tscn" id="4_d8lgm"]
[ext_resource type="PackedScene" uid="uid://uoxwjpmgg27a" path="res://entities/gold.tscn" id="5_yrfoq"]
[ext_resource type="PackedScene" uid="uid://djcwis8ycrq85" path="res://behaviours/sampler_priority.tscn" id="7_ech8d"]
[ext_resource type="PackedScene" uid="uid://dk1ipq7dhkhf3" path="res://behaviours/move_straight.tscn" id="8_ffcw0"]
[ext_resource type="PackedScene" uid="uid://cm67ko1k6kn4u" path="res://behaviours/priority.tscn" id="9_2wb1b"]
[ext_resource type="PackedScene" uid="uid://g8t6dt0ye6n3" path="res://behaviours/timer_stddev.tscn" id="10_phvea"]
[ext_resource type="PackedScene" uid="uid://cml7rqvyfuagx" path="res://behaviours/move_towards.tscn" id="11_4ra22"]
[ext_resource type="PackedScene" uid="uid://ctpn4hvkhxoi3" path="res://behaviours/tracker_edible.tscn" id="12_dr2oe"]
[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="13_mwxuf"]
[ext_resource type="PackedScene" uid="uid://rx24bppccih7" path="res://behaviours/move_physics.tscn" id="14_p3w0g"]
[ext_resource type="PackedScene" uid="uid://jg7qkbswgqjc" path="res://behaviours/eater.tscn" id="14_w2h8x"]
[ext_resource type="PackedScene" uid="uid://dijcjahkddudv" path="res://behaviours/draggable.tscn" id="15_otrbh"]
[ext_resource type="AudioStream" uid="uid://d0feiq5s6fnux" path="res://entities/imp_drag.wav" id="16_0frai"]
[ext_resource type="AudioStream" uid="uid://cwsg776c11xfc" path="res://entities/fall.ogg" id="17_lib0h"]
[ext_resource type="AudioStream" uid="uid://c1yuksnjdd6g2" path="res://entities/imp_eat.ogg" id="19_7la6c"]
[sub_resource type="CircleShape2D" id="CircleShape2D_ide4n"]
radius = 8.0
radius = 32.0
[sub_resource type="CircleShape2D" id="CircleShape2D_1bmhf"]
radius = 256.0
[sub_resource type="CircleShape2D" id="CircleShape2D_50iad"]
radius = 32.0
[sub_resource type="CircleShape2D" id="CircleShape2D_qhk1q"]
radius = 40.0
[node name="Imp" type="CharacterBody2D"]
collision_layer = 8
collision_mask = 14
motion_mode = 1
script = ExtResource("1_dixpc")
[node name="Sprite" parent="." instance=ExtResource("2_eqcdi")]
@ -24,33 +45,103 @@ left_texture = ExtResource("3_qda0k")
right_texture = ExtResource("4_0sckn")
[node name="Shape" type="CollisionShape2D" parent="."]
scale = Vector2(4, 4)
shape = SubResource("CircleShape2D_ide4n")
[node name="Draggable" parent="." instance=ExtResource("3_4528r")]
scale = Vector2(4, 4)
[node name="DragSound" type="AudioStreamPlayer2D" parent="Draggable"]
scale = Vector2(0.5, 0.5)
[node name="DropSound" type="AudioStreamPlayer2D" parent="Draggable"]
scale = Vector2(0.5, 0.5)
[node name="EatTarget" parent="." instance=ExtResource("3_iybf3")]
scale = Vector2(2, 2)
tag = &"Sheep"
[node name="SkullSpawner" parent="." instance=ExtResource("4_d8lgm")]
[node name="GoldSpawner" parent="." instance=ExtResource("4_d8lgm")]
scene = ExtResource("5_yrfoq")
[node name="Spawner" parent="." instance=ExtResource("4_d8lgm")]
scene = ExtResource("5_yrfoq")
[node name="Timer" type="Timer" parent="Spawner"]
wait_time = 0.8
[node name="TimerStddev" parent="GoldSpawner" instance=ExtResource("10_phvea")]
autostart = true
mean_secs = 5.0
deviation = 4.0
min_secs = 1.0
max_secs = 9.0
[connection signal="move" from="Draggable" to="." method="_on_draggable_move"]
[connection signal="eaten" from="EatTarget" to="." method="_on_eat_target_eaten"]
[connection signal="move" from="EatTarget" to="." method="_on_move"]
[connection signal="timeout" from="Spawner/Timer" to="Spawner" method="spawn"]
[node name="MovementSampler" parent="." node_paths=PackedStringArray("possibilities") instance=ExtResource("7_ech8d")]
possibilities = [NodePath("../MovementWander/WanderPriority"), NodePath("../MovementHunt/HuntPriority"), NodePath("../MovementDrag/DragPriority")]
[node name="MovementWander" parent="." instance=ExtResource("8_ffcw0")]
speed = 25.0
enabled = false
[node name="WanderPriority" parent="MovementWander" instance=ExtResource("9_2wb1b")]
default_priority = 10
alternative_priority = 10
[node name="ChangeDirectionTimer" parent="MovementWander" instance=ExtResource("10_phvea")]
autostart = true
mean_secs = 2.0
deviation = 2.0
min_secs = 0.6
max_secs = 3.0
[node name="MovementHunt" parent="." instance=ExtResource("11_4ra22")]
speed = 140.0
enabled = false
[node name="HuntPriority" parent="MovementHunt" instance=ExtResource("9_2wb1b")]
alternative_priority = 40
[node name="TrackerMeat" parent="MovementHunt" instance=ExtResource("12_dr2oe")]
acceptable_diets = Array[StringName]([&"Meat"])
[node name="Shape" type="CollisionShape2D" parent="MovementHunt/TrackerMeat"]
shape = SubResource("CircleShape2D_1bmhf")
debug_color = Color(1, 0.498039, 0, 0)
[node name="TargetPicker" parent="MovementHunt/TrackerMeat" node_paths=PackedStringArray("tracker") instance=ExtResource("13_mwxuf")]
tracker = NodePath("..")
[node name="MovementDrag" parent="." instance=ExtResource("14_p3w0g")]
enabled = false
[node name="DragPriority" parent="MovementDrag" instance=ExtResource("9_2wb1b")]
alternative_priority = 50
[node name="Draggable" parent="MovementDrag" instance=ExtResource("15_otrbh")]
[node name="Shape" type="CollisionShape2D" parent="MovementDrag/Draggable"]
shape = SubResource("CircleShape2D_50iad")
debug_color = Color(1, 1, 1, 0)
[node name="DragSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("16_0frai")
[node name="FallSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("17_lib0h")
[node name="Eater" parent="." instance=ExtResource("14_w2h8x")]
acceptable_diets = Array[StringName]([&"Meat"])
[node name="Shape" type="CollisionShape2D" parent="Eater"]
shape = SubResource("CircleShape2D_qhk1q")
debug_color = Color(1, 0, 0, 0)
[node name="EatSound" type="AudioStreamPlayer2D" parent="Eater"]
stream = ExtResource("19_7la6c")
[connection signal="timeout" from="GoldSpawner/TimerStddev" to="GoldSpawner" method="spawn"]
[connection signal="ready" from="MovementSampler" to="MovementSampler" method="enable"]
[connection signal="changed_direction" from="MovementWander" to="MovementWander/WanderPriority" method="priority_conditional"]
[connection signal="move" from="MovementWander" to="." method="_on_move"]
[connection signal="priority_changed_no_args" from="MovementWander/WanderPriority" to="MovementSampler" method="enable"]
[connection signal="timeout" from="MovementWander/ChangeDirectionTimer" to="MovementWander" method="randomize_direction"]
[connection signal="changed_target" from="MovementHunt" to="MovementHunt/HuntPriority" method="priority_conditional"]
[connection signal="move" from="MovementHunt" to="." method="_on_move"]
[connection signal="priority_changed_no_args" from="MovementHunt/HuntPriority" to="MovementSampler" method="enable"]
[connection signal="tracked" from="MovementHunt/TrackerMeat" to="MovementHunt/TrackerMeat/TargetPicker" method="sample_target_if_null" unbinds=1]
[connection signal="untracked" from="MovementHunt/TrackerMeat" to="MovementHunt/TrackerMeat/TargetPicker" method="clear_if_target"]
[connection signal="target_changed" from="MovementHunt/TrackerMeat/TargetPicker" to="MovementHunt" method="set_target" unbinds=1]
[connection signal="target_changed" from="MovementHunt/TrackerMeat/TargetPicker" to="MovementHunt/TrackerMeat/TargetPicker" method="sample_target_if_null" unbinds=2]
[connection signal="dragged" from="MovementDrag" to="." method="_on_dragged"]
[connection signal="dragged" from="MovementDrag" to="MovementDrag/DragPriority" method="priority_alternative" unbinds=1]
[connection signal="dragged" from="MovementDrag" to="MovementDrag/DragSound" method="play" unbinds=1]
[connection signal="fallen" from="MovementDrag" to="." method="_on_fallen"]
[connection signal="fallen" from="MovementDrag" to="MovementDrag/DragPriority" method="priority_default"]
[connection signal="fallen" from="MovementDrag" to="MovementDrag/FallSound" method="play"]
[connection signal="move" from="MovementDrag" to="." method="_on_move"]
[connection signal="priority_changed_no_args" from="MovementDrag/DragPriority" to="MovementSampler" method="enable"]
[connection signal="dragged" from="MovementDrag/Draggable" to="MovementDrag" method="drag"]
[connection signal="dropped" from="MovementDrag/Draggable" to="MovementDrag" method="drop"]
[connection signal="eaten" from="Eater" to="." method="_on_eater_eaten"]
[connection signal="eaten" from="Eater" to="Eater/EatSound" method="play" unbinds=1]

View file

@ -3,12 +3,12 @@
importer="wav"
type="AudioStreamWAV"
uid="uid://d0feiq5s6fnux"
path="res://.godot/imported/tank.wav-76da0daecf3b365c21fcd97289993799.sample"
path="res://.godot/imported/imp_drag.wav-e4ed42c6f5f4ccfe6d180bc00d8af7df.sample"
[deps]
source_file="res://temp/tank.wav"
dest_files=["res://.godot/imported/tank.wav-76da0daecf3b365c21fcd97289993799.sample"]
source_file="res://entities/imp_drag.wav"
dest_files=["res://.godot/imported/imp_drag.wav-e4ed42c6f5f4ccfe6d180bc00d8af7df.sample"]
[params]

BIN
entities/imp_eat.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View file

@ -0,0 +1,19 @@
[remap]
importer="oggvorbisstr"
type="AudioStreamOggVorbis"
uid="uid://c1yuksnjdd6g2"
path="res://.godot/imported/imp_eat.ogg-8244e5ac229d57fa0fbf148a2e9862db.oggvorbisstr"
[deps]
source_file="res://entities/imp_eat.ogg"
dest_files=["res://.godot/imported/imp_eat.ogg-8244e5ac229d57fa0fbf148a2e9862db.oggvorbisstr"]
[params]
loop=false
loop_offset=0
bpm=0
beat_count=0
bar_beats=4

16
entities/monocle.gd Normal file
View file

@ -0,0 +1,16 @@
extends CharacterBody2D
class_name Monocle
func _on_move(movement: Vector2) -> void:
move_and_collide(movement)
func _on_dragged(_cursor: Cursor) -> void:
collision_layer = 16
collision_mask = 18
z_index = 1
func _on_fallen() -> void:
collision_layer = 8
collision_mask = 14
z_index = 0

View file

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://d3tb6ypb36v8e"
path="res://.godot/imported/pickup_monocle.png-7a9e8cda4415a7ebfbddb870020ff730.ctex"
path="res://.godot/imported/monocle.png-2e39f2ebd2473082b74edcdb99c2e85d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://temp/pickup_monocle.png"
dest_files=["res://.godot/imported/pickup_monocle.png-7a9e8cda4415a7ebfbddb870020ff730.ctex"]
source_file="res://entities/monocle.png"
dest_files=["res://.godot/imported/monocle.png-2e39f2ebd2473082b74edcdb99c2e85d.ctex"]
[params]

49
entities/monocle.tscn Normal file
View file

@ -0,0 +1,49 @@
[gd_scene load_steps=9 format=3 uid="uid://b04xhv32ypi42"]
[ext_resource type="Script" path="res://entities/monocle.gd" id="1_ehpfj"]
[ext_resource type="Texture2D" uid="uid://d3tb6ypb36v8e" path="res://entities/monocle.png" id="1_omrit"]
[ext_resource type="PackedScene" uid="uid://rx24bppccih7" path="res://behaviours/move_physics.tscn" id="2_jgnsw"]
[ext_resource type="PackedScene" uid="uid://dijcjahkddudv" path="res://behaviours/draggable.tscn" id="3_e0ni5"]
[ext_resource type="AudioStream" uid="uid://dgd1ldpffk6ql" path="res://entities/monocle_drag.wav" id="5_bs8m7"]
[ext_resource type="AudioStream" uid="uid://cwsg776c11xfc" path="res://entities/fall.ogg" id="5_grwug"]
[sub_resource type="CircleShape2D" id="CircleShape2D_o7chm"]
radius = 12.0
[sub_resource type="CircleShape2D" id="CircleShape2D_juisb"]
radius = 12.0
[node name="Monocle" type="CharacterBody2D"]
collision_layer = 8
collision_mask = 14
motion_mode = 1
script = ExtResource("1_ehpfj")
[node name="Sprite" type="Sprite2D" parent="."]
scale = Vector2(2, 2)
texture = ExtResource("1_omrit")
[node name="Shape" type="CollisionShape2D" parent="."]
shape = SubResource("CircleShape2D_o7chm")
[node name="MovementDrag" parent="." instance=ExtResource("2_jgnsw")]
[node name="Draggable" parent="MovementDrag" instance=ExtResource("3_e0ni5")]
[node name="Shape" type="CollisionShape2D" parent="MovementDrag/Draggable"]
shape = SubResource("CircleShape2D_juisb")
debug_color = Color(1, 1, 1, 0)
[node name="DragSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("5_bs8m7")
[node name="FallSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("5_grwug")
[connection signal="dragged" from="MovementDrag" to="." method="_on_dragged"]
[connection signal="dragged" from="MovementDrag" to="MovementDrag/DragSound" method="play" unbinds=1]
[connection signal="fallen" from="MovementDrag" to="." method="_on_fallen"]
[connection signal="fallen" from="MovementDrag" to="MovementDrag/FallSound" method="play"]
[connection signal="move" from="MovementDrag" to="." method="_on_move"]
[connection signal="dragged" from="MovementDrag/Draggable" to="MovementDrag" method="drag"]
[connection signal="dropped" from="MovementDrag/Draggable" to="MovementDrag" method="drop"]

View file

@ -3,12 +3,12 @@
importer="wav"
type="AudioStreamWAV"
uid="uid://dgd1ldpffk6ql"
path="res://.godot/imported/pop.wav-5c8ab1a460889e6b7e24366eae5d4a3a.sample"
path="res://.godot/imported/monocle_drag.wav-d899e772e1792f41cd5a6ddac30bd2f6.sample"
[deps]
source_file="res://temp/pop.wav"
dest_files=["res://.godot/imported/pop.wav-5c8ab1a460889e6b7e24366eae5d4a3a.sample"]
source_file="res://entities/monocle_drag.wav"
dest_files=["res://.godot/imported/monocle_drag.wav-d899e772e1792f41cd5a6ddac30bd2f6.sample"]
[params]

View file

@ -2,10 +2,7 @@ extends CharacterBody2D
class_name Sheep
@onready var draggable: Draggable = $"Draggable"
@onready var sprite: SpriteLeftRight = $"Sprite"
@onready var drag_sound: AudioStreamPlayer2D = $"Draggable/DragSound"
@onready var drop_sound: AudioStreamPlayer2D = $"Draggable/DropSound"
@onready var animator: AnimationPlayer = $"Animator"
@ -13,19 +10,15 @@ func _ready() -> void:
animator.play("RESET")
func _on_move(movement: Vector2) -> void:
if not draggable.being_dragged:
move_and_collide(movement)
sprite.handle_move(movement)
move_and_collide(movement)
sprite.handle_move(movement)
func _on_drag_move(movement: Vector2) -> void:
if draggable.being_dragged:
move_and_collide(movement)
sprite.handle_move(movement)
func _on_dragged(_cursor: Cursor) -> void:
collision_layer = 16
collision_mask = 18
z_index = 1
func _on_draggable_dragged() -> void:
drag_sound.play()
animator.play("wobble")
func _on_draggable_dropped() -> void:
drop_sound.play()
animator.play("RESET")
func _on_fallen() -> void:
collision_layer = 8
collision_mask = 14
z_index = 0

View file

@ -1,36 +1,26 @@
[gd_scene load_steps=15 format=3 uid="uid://bc2bm8lbol18w"]
[gd_scene load_steps=24 format=3 uid="uid://bc2bm8lbol18w"]
[ext_resource type="Script" path="res://entities/sheep.gd" id="1_4dmll"]
[ext_resource type="Texture2D" uid="uid://iljp5yn3ehfk" path="res://entities/sheep_left.png" id="2_t13f5"]
[ext_resource type="PackedScene" uid="uid://bvrxvrjlo5130" path="res://behaviours/move_towards_mouse.tscn" id="2_tfd2i"]
[ext_resource type="PackedScene" uid="uid://bxbjfev0lhwws" path="res://behaviours/sprite_left_right.tscn" id="2_xbkrm"]
[ext_resource type="PackedScene" uid="uid://dijcjahkddudv" path="res://behaviours/draggable.tscn" id="3_8ku7r"]
[ext_resource type="Texture2D" uid="uid://cxtmas4g0v6en" path="res://entities/sheep_right.png" id="4_5qoof"]
[ext_resource type="AudioStream" uid="uid://buxgivpkh8dyl" path="res://entities/drop.wav" id="4_nxjnl"]
[ext_resource type="AudioStream" uid="uid://bmfscpnugaejk" path="res://entities/sheep_drag.wav" id="4_oalqu"]
[ext_resource type="PackedScene" uid="uid://dfdr3e32lohq" path="res://behaviours/edible.tscn" id="6_3odsh"]
[ext_resource type="PackedScene" uid="uid://djcwis8ycrq85" path="res://behaviours/sampler_priority.tscn" id="9_s5lod"]
[ext_resource type="PackedScene" uid="uid://dk1ipq7dhkhf3" path="res://behaviours/move_straight.tscn" id="10_05kcd"]
[ext_resource type="PackedScene" uid="uid://cm67ko1k6kn4u" path="res://behaviours/priority.tscn" id="11_0jlmk"]
[ext_resource type="PackedScene" uid="uid://g8t6dt0ye6n3" path="res://behaviours/timer_stddev.tscn" id="12_c45uk"]
[ext_resource type="PackedScene" uid="uid://cml7rqvyfuagx" path="res://behaviours/move_towards.tscn" id="12_x2g3x"]
[ext_resource type="PackedScene" uid="uid://cbg5kgwxusvxf" path="res://behaviours/cursor_detector.tscn" id="13_5fkdr"]
[ext_resource type="PackedScene" uid="uid://dti7l0d40hhgt" path="res://behaviours/target_picker.tscn" id="13_jf6em"]
[ext_resource type="PackedScene" uid="uid://dijcjahkddudv" path="res://behaviours/draggable.tscn" id="14_0b1hs"]
[ext_resource type="PackedScene" uid="uid://rx24bppccih7" path="res://behaviours/move_physics.tscn" id="14_3wojv"]
[ext_resource type="PackedScene" uid="uid://c5pyp5hvthdof" path="res://behaviours/tracker_tracker.tscn" id="14_eqowb"]
[ext_resource type="AudioStream" uid="uid://bmfscpnugaejk" path="res://entities/sheep_drag.wav" id="16_nswfl"]
[ext_resource type="AudioStream" uid="uid://cwsg776c11xfc" path="res://entities/fall.ogg" id="17_8kst2"]
[sub_resource type="CircleShape2D" id="CircleShape2D_c5tcn"]
radius = 8.0
[sub_resource type="Animation" id="Animation_lxieb"]
resource_name = "wobble"
length = 3.0
loop_mode = 1
step = 0.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5, 2, 3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [0.0, -0.261799, 0.0, 0.261799, 0.0]
}
[sub_resource type="Animation" id="Animation_gokbg"]
length = 0.001
tracks/0/type = "value"
@ -64,6 +54,24 @@ tracks/0/keys = {
"values": [Vector2(0, 0), Vector2(1, 1), Vector2(-1, -1), Vector2(-1, 0), Vector2(1, -1), Vector2(-1, 1), Vector2(1, 1), Vector2(1, 0), Vector2(-1, -1), Vector2(1, 0), Vector2(0, -1)]
}
[sub_resource type="Animation" id="Animation_lxieb"]
resource_name = "wobble"
length = 3.0
loop_mode = 1
step = 0.5
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite:rotation")
tracks/0/interp = 2
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1.5, 2, 3),
"transitions": PackedFloat32Array(1, 1, 1, 1, 1),
"update": 0,
"values": [0.0, -0.261799, 0.0, 0.261799, 0.0]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_6mutq"]
_data = {
"RESET": SubResource("Animation_gokbg"),
@ -71,9 +79,13 @@ _data = {
"wobble": SubResource("Animation_lxieb")
}
[sub_resource type="CircleShape2D" id="CircleShape2D_etpf6"]
radius = 144.0
[node name="Sheep" type="CharacterBody2D"]
collision_layer = 8
collision_mask = 14
motion_mode = 1
script = ExtResource("1_4dmll")
[node name="Sprite" parent="." instance=ExtResource("2_xbkrm")]
@ -87,31 +99,124 @@ right_texture = ExtResource("4_5qoof")
scale = Vector2(3, 3)
shape = SubResource("CircleShape2D_c5tcn")
[node name="MoveTowardsMouse" parent="." instance=ExtResource("2_tfd2i")]
scale = Vector2(30, 30)
speed = -30.0
can_detach = true
[node name="Draggable" parent="." instance=ExtResource("3_8ku7r")]
scale = Vector2(3, 3)
[node name="DragSound" type="AudioStreamPlayer2D" parent="Draggable"]
scale = Vector2(0.5, 0.5)
stream = ExtResource("4_oalqu")
[node name="DropSound" type="AudioStreamPlayer2D" parent="Draggable"]
scale = Vector2(0.5, 0.5)
stream = ExtResource("4_nxjnl")
[node name="Edible" parent="." instance=ExtResource("6_3odsh")]
tag = &"Sheep"
[node name="Animator" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_6mutq")
}
[connection signal="move" from="MoveTowardsMouse" to="." method="_on_move"]
[connection signal="dragged" from="Draggable" to="." method="_on_draggable_dragged"]
[connection signal="dropped" from="Draggable" to="." method="_on_draggable_dropped"]
[connection signal="move" from="Draggable" to="." method="_on_drag_move"]
[node name="Edible" parent="." instance=ExtResource("6_3odsh")]
diet = &"Meat"
[node name="MovementSampler" parent="." node_paths=PackedStringArray("possibilities") instance=ExtResource("9_s5lod")]
possibilities = [NodePath("../MovementIdle/IdlePriority"), NodePath("../MovementWander/WanderPriority"), NodePath("../MovementRunFromMouse/RunFromMousePriority"), NodePath("../MovementRunFromHunter/RunFromHunterPriority"), NodePath("../MovementDrag/DragPriority")]
[node name="MovementIdle" parent="." instance=ExtResource("10_05kcd")]
speed = 0.0
enabled = false
[node name="IdlePriority" parent="MovementIdle" instance=ExtResource("11_0jlmk")]
alternative_priority = 0
[node name="BoredTimer" parent="MovementIdle" instance=ExtResource("12_c45uk")]
one_shot = true
autostart = true
mean_secs = 3.0
min_secs = 1.0
max_secs = 5.0
[node name="MovementWander" parent="." instance=ExtResource("10_05kcd")]
speed = 33.0
enabled = false
[node name="WanderPriority" parent="MovementWander" instance=ExtResource("11_0jlmk")]
alternative_priority = 20
[node name="TiredTimer" parent="MovementWander" instance=ExtResource("12_c45uk")]
one_shot = true
min_secs = 0.3
max_secs = 1.5
[node name="MovementRunFromMouse" parent="." instance=ExtResource("12_x2g3x")]
speed = -66.0
enabled = false
[node name="RunFromMousePriority" parent="MovementRunFromMouse" instance=ExtResource("11_0jlmk")]
alternative_priority = 30
[node name="CursorSense" parent="MovementRunFromMouse" instance=ExtResource("13_5fkdr")]
[node name="Shape" type="CollisionShape2D" parent="MovementRunFromMouse/CursorSense"]
shape = SubResource("CircleShape2D_etpf6")
debug_color = Color(1, 1, 0, 0)
[node name="MovementRunFromHunter" parent="." instance=ExtResource("12_x2g3x")]
speed = -66.0
enabled = false
[node name="RunFromHunterPriority" parent="MovementRunFromHunter" instance=ExtResource("11_0jlmk")]
alternative_priority = 40
[node name="HunterSense" parent="MovementRunFromHunter" instance=ExtResource("14_eqowb")]
[node name="Shape" type="CollisionShape2D" parent="MovementRunFromHunter/HunterSense"]
shape = SubResource("CircleShape2D_etpf6")
debug_color = Color(1, 1, 0, 0)
[node name="TargetPicker" parent="MovementRunFromHunter/HunterSense" node_paths=PackedStringArray("tracker") instance=ExtResource("13_jf6em")]
tracker = NodePath("..")
[node name="MovementDrag" parent="." instance=ExtResource("14_3wojv")]
enabled = false
[node name="DragPriority" parent="MovementDrag" instance=ExtResource("11_0jlmk")]
alternative_priority = 50
[node name="Draggable" parent="MovementDrag" instance=ExtResource("14_0b1hs")]
[node name="Shape" type="CollisionShape2D" parent="MovementDrag/Draggable"]
scale = Vector2(3, 3)
shape = SubResource("CircleShape2D_c5tcn")
debug_color = Color(1, 1, 1, 0)
[node name="DragSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("16_nswfl")
[node name="FallSound" type="AudioStreamPlayer2D" parent="MovementDrag"]
stream = ExtResource("17_8kst2")
[connection signal="ready" from="MovementSampler" to="MovementSampler" method="enable"]
[connection signal="move" from="MovementIdle" to="." method="_on_move"]
[connection signal="move_disabled" from="MovementIdle" to="MovementIdle/BoredTimer" method="stop"]
[connection signal="move_enabled" from="MovementIdle" to="MovementIdle/BoredTimer" method="start"]
[connection signal="priority_changed_no_args" from="MovementIdle/IdlePriority" to="MovementSampler" method="enable"]
[connection signal="timeout" from="MovementIdle/BoredTimer" to="MovementWander" method="randomize_direction"]
[connection signal="changed_direction" from="MovementWander" to="MovementWander/WanderPriority" method="priority_conditional"]
[connection signal="move" from="MovementWander" to="." method="_on_move"]
[connection signal="move_disabled" from="MovementWander" to="MovementWander/TiredTimer" method="stop"]
[connection signal="move_enabled" from="MovementWander" to="MovementWander/TiredTimer" method="start"]
[connection signal="priority_changed_no_args" from="MovementWander/WanderPriority" to="MovementSampler" method="enable"]
[connection signal="timeout" from="MovementWander/TiredTimer" to="MovementWander" method="clear_direction"]
[connection signal="changed_target" from="MovementRunFromMouse" to="MovementRunFromMouse/RunFromMousePriority" method="priority_conditional"]
[connection signal="move" from="MovementRunFromMouse" to="." method="_on_move"]
[connection signal="move_enabled" from="MovementRunFromMouse" to="MovementWander" method="clear_direction"]
[connection signal="priority_changed_no_args" from="MovementRunFromMouse/RunFromMousePriority" to="MovementSampler" method="enable"]
[connection signal="cursor_entered" from="MovementRunFromMouse/CursorSense" to="MovementRunFromMouse" method="set_target"]
[connection signal="cursor_exited" from="MovementRunFromMouse/CursorSense" to="MovementRunFromMouse" method="clear_target" unbinds=1]
[connection signal="changed_target" from="MovementRunFromHunter" to="MovementRunFromHunter/RunFromHunterPriority" method="priority_conditional"]
[connection signal="move" from="MovementRunFromHunter" to="." method="_on_move"]
[connection signal="move_disabled" from="MovementRunFromHunter" to="MovementWander" method="clear_direction"]
[connection signal="priority_changed_no_args" from="MovementRunFromHunter/RunFromHunterPriority" to="MovementSampler" method="enable"]
[connection signal="tracked" from="MovementRunFromHunter/HunterSense" to="MovementRunFromHunter/HunterSense/TargetPicker" method="set_target_if_null"]
[connection signal="untracked" from="MovementRunFromHunter/HunterSense" to="MovementRunFromHunter/HunterSense/TargetPicker" method="clear_if_target"]
[connection signal="target_changed" from="MovementRunFromHunter/HunterSense/TargetPicker" to="MovementRunFromHunter" method="set_target" unbinds=1]
[connection signal="dragged" from="MovementDrag" to="." method="_on_dragged"]
[connection signal="dragged" from="MovementDrag" to="MovementDrag/DragPriority" method="priority_alternative" unbinds=1]
[connection signal="dragged" from="MovementDrag" to="MovementDrag/DragSound" method="play" unbinds=1]
[connection signal="fallen" from="MovementDrag" to="." method="_on_fallen"]
[connection signal="fallen" from="MovementDrag" to="MovementDrag/DragPriority" method="priority_default"]
[connection signal="fallen" from="MovementDrag" to="MovementDrag/FallSound" method="play"]
[connection signal="move" from="MovementDrag" to="." method="_on_move"]
[connection signal="move_enabled" from="MovementDrag" to="MovementWander" method="clear_direction"]
[connection signal="priority_changed_no_args" from="MovementDrag/DragPriority" to="MovementSampler" method="enable"]
[connection signal="dragged" from="MovementDrag/Draggable" to="MovementDrag" method="drag"]
[connection signal="dropped" from="MovementDrag/Draggable" to="MovementDrag" method="drop"]

View file

@ -1,119 +0,0 @@
extends RigidBody2D
var initial_self_position: Vector2 = Vector2.ZERO
var initial_mouse_position: Vector2 = Vector2.ZERO
@onready var rand_walk_timer: Timer = Timer.new()
var rng = RandomNumberGenerator.new()
enum State {STATE_IDLE, STATE_WALK, STATE_PICKED, STATE_RUN, STATE_THROWN}
var state: State = State.STATE_IDLE
var walk_dir: Vector2 = Vector2.ZERO
var last_dir: int = 1
var last_mouse_pos: Vector2 = Vector2.ZERO
@export var min_run_dist = 200
@export var max_run_dist = 250
@export var walk_speed = 150
@export var run_speed = 500
@export var drag_damp = 40
@export var normal_damp = 4
@export var thrown_damp = 2
# Called when the node enters the scene tree for the first time.
func _ready():
add_child(rand_walk_timer)
rand_walk_timer.one_shot = true;
rand_walk_timer.connect("timeout", _on_timer_timeout)
init_timer()
func init_timer():
if state == State.STATE_IDLE:
var rand_time = max(0, rng.randfn(4, 1.5))
rand_walk_timer.start(rand_time)
elif state == State.STATE_WALK:
rand_walk_timer.start(5)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
# Update state
var curr_mpos = get_viewport().get_mouse_position()
last_mouse_pos = curr_mpos
if state == State.STATE_PICKED and not Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
pick_down()
var mouse_dis = position.distance_to(curr_mpos)
if (state == State.STATE_IDLE or state == State.STATE_WALK) and mouse_dis < min_run_dist:
# Run away from mouse
state = State.STATE_RUN
rand_walk_timer.stop()
elif state == State.STATE_RUN and mouse_dis > max_run_dist:
state = State.STATE_IDLE
init_timer()
func _physics_process(delta):
gravity_scale = 0
if state == State.STATE_THROWN and linear_velocity.length() < 300:
linear_velocity = Vector2.ZERO
state = State.STATE_WALK
init_timer()
var force = Vector2.ZERO
if state == State.STATE_WALK:
force = walk_speed * walk_dir
elif state == State.STATE_RUN:
var run_dir = -position.direction_to(last_mouse_pos)
force = run_speed * run_dir
elif state == State.STATE_PICKED:
var dest_position = initial_self_position + (last_mouse_pos - initial_mouse_position)
apply_central_force(50 * (dest_position - position) * dest_position.distance_to(position) * delta)
else:
pass
if force.length_squared() > 0.001:
apply_central_force(force)
last_dir = sign(force.dot(Vector2.LEFT))
scale.x = last_dir
if state == State.STATE_PICKED:
linear_damp = drag_damp
elif state == State.STATE_THROWN:
linear_damp = thrown_damp
else:
linear_damp = normal_damp
func _on_input_event(viewport, event, shape_idx):
if event is InputEventMouseButton:
var was_picked_up = state == State.STATE_PICKED
var is_picked_up = event.pressed
initial_mouse_position = event.position
initial_self_position = position
if not was_picked_up and is_picked_up:
state = State.STATE_PICKED
rand_walk_timer.stop()
elif was_picked_up and not is_picked_up:
pick_down()
func pick_down():
state = State.STATE_THROWN
init_timer()
func _on_timer_timeout():
if state == State.STATE_IDLE:
state = State.STATE_WALK
walk_dir = Vector2.from_angle(rng.randf_range(0, 2*PI))
elif state == State.STATE_WALK:
state = State.STATE_IDLE
init_timer()

16
entities/skull.gd Normal file
View file

@ -0,0 +1,16 @@
extends CharacterBody2D
class_name Skull
func _on_move(movement: Vector2) -> void:
move_and_collide(movement)
func _on_dragged(_cursor: Cursor) -> void:
collision_layer = 16
collision_mask = 18
z_index = 1
func _on_fallen() -> void:
collision_layer = 8
collision_mask = 14
z_index = 0

View file

@ -3,15 +3,15 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://dwvvwjdexdywh"
path="res://.godot/imported/pickup_skull.png-c05653658414d7be9a8a5454887e620a.ctex"
path="res://.godot/imported/skull.png-eb9ec0d464004e0ca27a71e2a33a9dd3.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://temp/pickup_skull.png"
dest_files=["res://.godot/imported/pickup_skull.png-c05653658414d7be9a8a5454887e620a.ctex"]
source_file="res://entities/skull.png"
dest_files=["res://.godot/imported/skull.png-eb9ec0d464004e0ca27a71e2a33a9dd3.ctex"]
[params]

Some files were not shown because too many files have changed in this diff Show more