Make some test with terrain generator

This commit is contained in:
2026-02-01 20:22:20 +01:00
parent 571605de8a
commit fe11763496
22 changed files with 1252 additions and 117 deletions

View File

@@ -0,0 +1,461 @@
---
name: godot-gdscript
description: "Develops GDScript code for Godot 4.6 projects. Use when writing, editing, or debugging GDScript files, creating nodes, signals, exports, or any Godot game development task."
---
# Godot 4.6 GDScript Development
Write idiomatic GDScript for Godot 4.6 following these conventions and language features.
## File Structure
```gdscript
@tool # Optional: runs in editor
@icon("res://path/to/icon.svg") # Optional: custom icon
class_name MyClass # Optional: registers global class
extends BaseClass # Required (defaults to RefCounted)
## Signals
signal health_changed(old_value, new_value)
## Enums
enum State { IDLE, RUNNING, JUMPING }
## Constants
const MAX_SPEED = 100.0
## Exports (inspector properties)
@export var speed: float = 50.0
@export_range(0, 100) var health: int = 100
## Public variables
var velocity: Vector2 = Vector2.ZERO
## Private variables (convention: prefix with _)
var _internal_state: int = 0
## @onready variables (initialized in _ready)
@onready var sprite: Sprite2D = $Sprite2D
## Static variables
static var instance_count: int = 0
## Built-in virtual methods
func _init():
pass
func _ready():
pass
func _process(delta: float) -> void:
pass
func _physics_process(delta: float) -> void:
pass
## Public methods
func take_damage(amount: int) -> void:
pass
## Private methods
func _calculate_something() -> float:
return 0.0
## Static methods
static func get_instance_count() -> int:
return instance_count
```
## Type System
### Type Hints
```gdscript
var my_int: int = 5
var my_string: String = "hello"
var my_node: Node2D = null
var inferred := Vector2(1, 2) # Type inferred as Vector2
func my_func(param: int, optional: String = "default") -> bool:
return true
```
### Typed Arrays and Dictionaries
```gdscript
var int_array: Array[int] = [1, 2, 3]
var node_array: Array[Node] = []
var typed_dict: Dictionary[String, int] = {"a": 1, "b": 2}
```
### Casting
```gdscript
var node := $Sprite as Sprite2D # Returns null if wrong type
if node is Sprite2D:
node.texture = some_texture
```
## Common Patterns
### Signals
```gdscript
signal damage_taken(amount: int)
func take_damage(amount: int) -> void:
health -= amount
damage_taken.emit(amount)
# Connecting signals
func _ready():
$Button.pressed.connect(_on_button_pressed)
# With bound arguments
$Enemy.died.connect(_on_enemy_died.bind(enemy_name))
func _on_button_pressed():
pass
```
### Properties (Setters/Getters)
```gdscript
var health: int = 100:
get:
return health
set(value):
health = clamp(value, 0, max_health)
health_changed.emit(health)
```
### Export Annotations
```gdscript
@export var speed: float = 10.0
@export_range(0, 100, 1) var health: int = 100
@export_enum("Walk", "Run", "Jump") var movement: int
@export_file("*.png") var texture_path: String
@export_dir var save_directory: String
@export_node_path("Sprite2D", "Sprite3D") var sprite_path: NodePath
@export_flags("Fire", "Water", "Earth", "Wind") var elements: int
@export_group("Movement")
@export var walk_speed: float
@export var run_speed: float
@export_subgroup("Physics")
@export var gravity: float
```
### Node References
```gdscript
@onready var player := $Player as CharacterBody2D
@onready var unique_node := %UniqueNodeName # Scene-unique node
# Get nodes dynamically
var child = get_node("Path/To/Child")
var parent = get_parent()
```
### Awaiting Signals/Coroutines
```gdscript
func async_operation() -> void:
await get_tree().create_timer(1.0).timeout
print("1 second passed")
var result = await some_async_func()
print(result)
```
### Match Statements
```gdscript
match state:
State.IDLE:
play_idle_animation()
State.RUNNING:
play_run_animation()
_:
push_warning("Unknown state")
# Pattern matching with guards
match point:
[var x, var y] when x == y:
print("On diagonal")
[var x, var y]:
print("Point: ", x, ", ", y)
```
### Lambda Functions
```gdscript
var double = func(x): return x * 2
print(double.call(5)) # 10
# With type hints
var add: Callable = func(a: int, b: int) -> int: return a + b
```
### Variadic Functions (4.5+)
```gdscript
func log_values(prefix: String, ...values: Array) -> void:
for v in values:
print(prefix, v)
```
## Built-in Types Reference
| Type | Description |
|------|-------------|
| `null` | Empty value |
| `bool` | `true` or `false` |
| `int` | 64-bit integer |
| `float` | 64-bit float |
| `String` | Unicode string |
| `StringName` | Interned string (fast comparison) |
| `NodePath` | Path to node/property |
| `Vector2/Vector2i` | 2D vector |
| `Vector3/Vector3i` | 3D vector |
| `Rect2` | 2D rectangle |
| `Transform2D/Transform3D` | Transformation matrix |
| `Color` | RGBA color |
| `Array` | Dynamic array |
| `Dictionary` | Key-value map |
| `Callable` | Function reference |
| `Signal` | Signal reference |
## Memory Management
- `RefCounted` subclasses: Automatically freed when no references
- `Node` subclasses: Must call `queue_free()` or `free()`
- Use `weakref()` to avoid reference cycles
```gdscript
var weak = weakref(some_object)
if weak.get_ref():
weak.get_ref().do_something()
if is_instance_valid(node):
node.queue_free()
```
## Abstract Classes (4.5+)
```gdscript
@abstract
class_name BaseEnemy
extends CharacterBody2D
@abstract func attack() -> void
class Zombie extends BaseEnemy:
func attack() -> void:
# Must implement abstract method
melee_attack()
```
## Style Guide
### Naming Conventions
| Type | Convention | Example |
|------|------------|---------|
| File names | snake_case | `yaml_parser.gd` |
| Class names | PascalCase | `class_name YAMLParser` |
| Node names | PascalCase | `Camera3D`, `Player` |
| Functions | snake_case | `func load_level():` |
| Variables | snake_case | `var particle_effect` |
| Signals | snake_case (past tense) | `signal door_opened` |
| Constants | CONSTANT_CASE | `const MAX_SPEED = 200` |
| Enum names | PascalCase | `enum Element` |
| Enum members | CONSTANT_CASE | `{EARTH, WATER, AIR}` |
### Private Members
Prepend underscore for private/virtual methods and variables:
```gdscript
var _internal_state: int = 0
func _calculate_damage() -> int:
return 0
```
### Code Order
Organize scripts in this order:
1. `@tool` (if needed)
2. `@icon`
3. `class_name`
4. `extends`
5. `## Documentation comments`
6. Signals
7. Enums
8. Constants
9. `@export` variables
10. Public variables
11. Private variables
12. `@onready` variables
13. Virtual methods (`_init`, `_ready`, `_process`, etc.)
14. Public methods
15. Private methods
16. Inner classes
### Formatting Rules
**Indentation**: Use tabs, not spaces.
**Blank lines**:
- Two blank lines between functions/class definitions
- One blank line to separate logical sections within functions
**Line length**: Keep under 100 characters (prefer 80).
**Comments**:
```gdscript
# Regular comment (space after #)
## Documentation comment
#var disabled_code # No space for commented code
#region Region Name
#endregion
```
**Multiline statements** - Use parentheses, put `and`/`or` at line start:
```gdscript
if (
is_valid
and has_permission
and not is_disabled
):
do_something()
```
**Enums** - One item per line:
```gdscript
enum State {
IDLE,
RUNNING,
JUMPING,
}
```
## Static Typing
Static typing catches errors at compile time, improves autocompletion, and enables performance optimizations.
### Basic Syntax
```gdscript
# Variables
var health: int = 100
var velocity: Vector2 = Vector2.ZERO
var player: CharacterBody2D
# Type inference with :=
var speed := 10.0 # Inferred as float
var position := Vector2.ZERO # Inferred as Vector2
# Constants (type optional but recommended for arrays)
const MAX_SPEED: float = 200.0
const ITEMS: Array[String] = ["sword", "shield"]
# Function parameters and return types
func calculate_damage(base: int, multiplier: float) -> int:
return int(base * multiplier)
# Void return type
func apply_damage(amount: int) -> void:
health -= amount
```
### Typed Collections
```gdscript
# Typed arrays
var enemies: Array[Enemy] = []
var scores: Array[int] = [10, 20, 30]
# Typed dictionaries (Godot 4.4+)
var inventory: Dictionary[String, int] = {"gold": 100}
var stats: Dictionary[StringName, float] = {}
# Typed for loops
for enemy: Enemy in enemies:
enemy.take_damage(10)
for name: String in ["Alice", "Bob"]:
print(name)
```
### Type Casting
```gdscript
# Safe casting with 'as' (returns null if wrong type)
var sprite := $Sprite as Sprite2D
if sprite:
sprite.texture = new_texture
# Type checking with 'is'
if node is CharacterBody2D:
var body: CharacterBody2D = node
body.move_and_slide()
# Casting node references for safe lines
@onready var timer := $Timer as Timer
@onready var player := $Player as CharacterBody2D
```
### Safe vs Unsafe Lines
The editor marks lines green (safe) or grey (unsafe):
```gdscript
# Safe - type is known
var timer: Timer = $Timer as Timer
# Unsafe - type could fail at runtime
var timer = $Timer # No type info
```
### Typed Global Scope Methods
Use typed versions for better performance:
```gdscript
# Prefer typed versions
var node: Node = instance_from_id(id) as Node # Safe
var clamped: int = clampi(value, 0, 100) # Typed int clamp
var lerped: float = lerpf(0.0, 1.0, 0.5) # Typed float lerp
# Typed math functions
var abs_val: int = absi(-5)
var max_val: float = maxf(a, b)
var min_val: int = mini(a, b)
```
### Safe Property/Method Access
```gdscript
# Unsafe - warnings if property doesn't exist on type
func process_node(node: Node2D) -> void:
if "custom_property" in node:
node.custom_property = 10 # UNSAFE_PROPERTY_ACCESS warning
# Safe - cast first, then access
func process_node_safe(node: Node2D) -> void:
if node is MyScript:
var typed: MyScript = node as MyScript
typed.custom_property = 10 # Safe
```
### Limitations
```gdscript
# Cannot type individual array/dict elements inline
var arr = [1, "two", 3.0] # Mixed types - can't specify
# Nested typed collections not supported
var nested: Array[Array[int]] # ERROR - not allowed
# Use this instead
var nested: Array[Array] = [[1, 2], [3, 4]]
```
### Recommended Editor Settings
Enable in **Project Settings > Debug > GDScript**:
- `UNTYPED_DECLARATION` - Warn on untyped variables
- `INFERRED_DECLARATION` - Prefer explicit over inferred types
- `UNSAFE_PROPERTY_ACCESS` - Warn on unsafe property access
- `UNSAFE_METHOD_ACCESS` - Warn on unsafe method calls
Enable in **Editor Settings > Text Editor > Completion**:
- **Add Type Hints** - Auto-add types on completion
## Best Practices
1. **Use static typing** - Improves performance and catches errors
2. **Prefer `@onready`** - For node references instead of `_ready()` assignments
3. **Use signals** - For decoupled communication between nodes
4. **Avoid `get_node()` in `_process()`** - Cache references with `@onready`
5. **Use `StringName` for frequent comparisons** - `&"my_string"`
6. **Group exports** - Use `@export_group` and `@export_subgroup`
7. **Document with `##`** - Double hash for documentation comments
8. **Declare locals near first use** - Don't declare at top of function
9. **Use past tense for signals** - `health_depleted`, `door_opened`
10. **Match file name to class** - `YAMLParser``yaml_parser.gd`