First godot-ci commit

This commit is contained in:
2025-05-13 13:29:35 +02:00
commit d3e99bc70e
47 changed files with 3158 additions and 0 deletions

7
scripts/Arena.gd Executable file
View File

@@ -0,0 +1,7 @@
extends Node2D
func _ready():
self.setup_arena()
func setup_arena() -> void:
$Background.lowlight()

22
scripts/Base.gd Executable file
View File

@@ -0,0 +1,22 @@
extends "res://scripts/ColoredEntity.gd"
const FULL_HEALTH: int = 3
var health: int = self.FULL_HEALTH
func _ready():
self.highlight()
func hit() -> void:
if health > 1:
self.health -= 1
else:
self.dead()
func dead() -> void:
pass
# --- Signals ---
func _on_Body_body_entered(body: Node):
body.queue_free()
self.hit()

48
scripts/Cannon.gd Normal file
View File

@@ -0,0 +1,48 @@
extends "res://scripts/ColoredEntity.gd"
@onready var Bullet: PackedScene = preload("res://scenes/Projectile.tscn")
const RATE_OF_CHANGE: float = 0.9
const UPPER_LIMIT: int = -89
const LOWER_LIMIT: int = -5
var angle: float = -45.0
func _ready():
self.highlight()
func _process(delta):
$Sprite2D.set_rotation(deg_to_rad(self.angle))
$Sprite2D.size.y = 24
func _input(event):
if Input.is_action_pressed("ui_up"):
if self.angle > UPPER_LIMIT:
self.move_up()
if Input.is_action_pressed("ui_down"):
if self.angle < LOWER_LIMIT:
self.move_down()
func move_up() -> void:
self.angle -= RATE_OF_CHANGE
func move_down() -> void:
self.angle += RATE_OF_CHANGE
func shoot() -> void:
if $FireCooldown.time_left == 0:
var NewBullet = Bullet.instantiate()
NewBullet.global_position = $Sprite2D/CannonTip.global_position
NewBullet.rotation_degrees = self.angle
var at: Vector2 = $Sprite2D/CannonTip.global_position - $Sprite2D/CannonBase.global_position
NewBullet.shoot(at)
var BulletSprite = NewBullet.get_node("Mask")
if self.highlighted:
BulletSprite.highlight()
else:
BulletSprite.lowlight()
NewBullet.setup(GLOBAL.SpriteType.BULLET, GLOBAL.BULLET_SPEED)
NewBullet.update_collision_layer()
$Projectiles.add_child(NewBullet)
$FireCooldown.start()

37
scripts/ColoredEntity.gd Executable file
View File

@@ -0,0 +1,37 @@
# Class with common color switch operations.
# Add to the group ColoredEntity if its color is not fixed and gets swapped with player input.
extends Node2D
var current_color: Color = GLOBAL.LOWLIGHT
var highlighted: bool = false
func _ready():
self.update_color()
func update_color() -> void:
if highlighted:
self.current_color = GLOBAL.HIGHLIGHT
else:
self.current_color = GLOBAL.LOWLIGHT
self.modulate = self.current_color
func swap_color() -> void:
if current_color == GLOBAL.LOWLIGHT:
self.highlight()
else:
self.lowlight()
func highlight():
current_color = GLOBAL.HIGHLIGHT
highlighted = true
self.update_color()
func lowlight():
current_color = GLOBAL.LOWLIGHT
highlighted = false
self.update_color()
func set_random_color() -> void:
randomize()
if randi() % 2 == 0:
self.swap_color()

40
scripts/EnemyGenerator.gd Normal file
View File

@@ -0,0 +1,40 @@
extends Node2D
@onready var EnemyScene: PackedScene = preload("res://scenes/Projectile.tscn")
signal start
signal stop
var Enemy
func _ready():
self.setup_enemy()
self.emit_signal("stop")
func setup_enemy() -> void:
self.Enemy = EnemyScene.instantiate()
Enemy.setup(GLOBAL.SpriteType.MISSILE, GLOBAL.MISSILE_SPEED["max"])
func spawn_and_shoot_enemy() -> void:
var Duplicate = Enemy.duplicate(Node.DUPLICATE_USE_INSTANTIATION)
Duplicate.set_random_color()
Duplicate.update_collision_layer()
$Enemies.add_child(Duplicate)
$SpawnArea/SpawnLocation.set_h_offset(randi())
Duplicate.global_position = $SpawnArea/SpawnLocation.position
var direction: Vector2 = (Vector2(0, 1080) - Duplicate.global_position).normalized()
var angle: float = Vector2(1, 0).angle_to(direction)
Duplicate.rotation = angle
Duplicate.shoot_missile(direction)
# --- Signals ---
func _on_SpawnTimer_timeout():
self.spawn_and_shoot_enemy()
func _on_EnemyGenerator_start():
$SpawnTimer.start()
func _on_EnemyGenerator_stop():
$SpawnTimer.stop()

44
scripts/GLOBAL.gd Executable file
View File

@@ -0,0 +1,44 @@
extends Node
enum SpriteType { BULLET = 0, MISSILE = 1 }
var theme_index: int = 0
var current_theme: Dictionary
var HIGHLIGHT: Color
var LOWLIGHT: Color
const COLORSET_PY: Dictionary = { "high": Color(1, 1, 0.25), "low": Color(0.50, 0, 1) }
const COLORSET_OB: Dictionary = { "high": Color(1, 0.56, 0), "low": Color(0, 0.40, 1) }
const COLORSET_PB: Dictionary = { "high": Color(1, 0.50, 1), "low": Color(0, 0.75, 1) }
const COLORS: Array = [
COLORSET_PY,
COLORSET_OB,
COLORSET_PB
]
const DEF_SPEED: float = 5.0
const MISSILE_SPEED: Dictionary = { "min": 30, "max": 60 }
const BULLET_SPEED: float = 10.0
const LOW_COLLISION: int = 2
const HIGH_COLLISION: int = 3
func _ready():
self.update_global_theme(self.theme_index)
func update_global_theme(index: int):
self.theme_index = index
self.current_theme = COLORS[theme_index]
self.HIGHLIGHT = self.current_theme["high"]
self.LOWLIGHT = self.current_theme["low"]
self.update_colored_entities()
func update_colored_entities() -> void:
var nodes: Array = self.get_tree().get_nodes_in_group("ColoredEntity")
for node in nodes:
node.update_color()
func swap_nodes_color() -> void:
var nodes: Array = self.get_tree().get_nodes_in_group("ColoredEntity")
for node in nodes:
node.swap_color()

4
scripts/Game.gd Executable file
View File

@@ -0,0 +1,4 @@
extends Node2D
func _ready():
pass

15
scripts/HUD.gd Executable file
View File

@@ -0,0 +1,15 @@
extends Control
func _ready():
pass
# --- Signals ---
func _on_Theme_Button_pressed(button_index: int) -> void:
GLOBAL.update_global_theme(button_index)
func _on_StartButton_pressed():
get_node("/root/Main").emit_signal("start_zoom_out")
get_node("/root/Main/Game/EnemyGenerator").emit_signal("start")
get_node("/root/Main/Game/Player").emit_signal("unblock")
self.hide()

25
scripts/Main.gd Executable file
View File

@@ -0,0 +1,25 @@
extends Node2D
signal start_zoom_out
const ZOOM_DELTA: float = 0.2
const MOVE_DELTA: float = 0.353
@onready var camera: Camera2D = $Path2D/PathFollow2D/MenuCamera
var camera_zooming: bool = false
func _process(delta: float):
if camera_zooming:
self.zoom_out_proccess(delta)
func zoom_out_proccess(delta: float) -> void:
var delta_speed = delta * ZOOM_DELTA
if camera.zoom < Vector2(1, 1):
camera.zoom += Vector2(delta_speed, delta_speed)
else:
self.camera_zooming = false
$Path2D/PathFollow2D.progress_ratio += delta * MOVE_DELTA
func _on_Main_start_zoom_out():
self.camera_zooming = true

25
scripts/Player.gd Executable file
View File

@@ -0,0 +1,25 @@
extends "res://scripts/ColoredEntity.gd"
signal unblock
var blocked_controls: bool = true
func _ready():
self.highlight()
func _input(event):
if blocked_controls:
return
if Input.is_action_just_pressed("swap"):
GLOBAL.swap_nodes_color()
if Input.is_action_pressed("fire"):
self.shoot_bullet()
func shoot_bullet() -> void:
$Cannon.shoot()
# --- Signals ---
func _on_Player_unblock():
self.blocked_controls = false

68
scripts/Projectile.gd Normal file
View File

@@ -0,0 +1,68 @@
extends RigidBody2D
var MissileSprite: Texture2D = load("res://resources/img/missile-placeholder.png")
var BulletSprite: Texture2D = load("res://resources/img/bullet-placeholder.png")
var bodies_in_area: Array = []
var sprite_type: int
var speed: float = GLOBAL.DEF_SPEED
var armed: bool = false
func _ready():
self.gravity_scale = 0.0
self.physics_material_override.friction = 0.0
self.contact_monitor = true
self.max_contacts_reported = 1
func setup(sprite_type: int, speed: float) -> void:
self.sprite_type = sprite_type
self.speed = speed
if sprite_type == GLOBAL.SpriteType.BULLET:
$Mask/Sprite2D.set_texture(self.BulletSprite)
self.armed = true
$ExplosionArea/ExplosionShape.disabled = false
else:
$Mask/Sprite2D.set_texture(self.MissileSprite)
func shoot(at: Vector2) -> void:
var direction = (at - self.global_position)
self.linear_velocity = at * speed
func shoot_missile(at: Vector2) -> void:
var direction = (at - self.global_position)
self.apply_central_force(at * GLOBAL.MISSILE_SPEED["max"])
func set_random_color() -> void:
$Mask.set_random_color()
func update_collision_layer() -> void:
if $Mask.highlighted:
self.set_collision_layer_value(GLOBAL.HIGH_COLLISION, 1)
self.set_collision_mask_value(GLOBAL.HIGH_COLLISION, 1)
$ExplosionArea.set_collision_layer_value(GLOBAL.HIGH_COLLISION, 1)
$ExplosionArea.set_collision_mask_value(GLOBAL.HIGH_COLLISION, 1)
else:
self.set_collision_layer_value(GLOBAL.LOW_COLLISION, 1)
self.set_collision_mask_value(GLOBAL.LOW_COLLISION, 1)
$ExplosionArea.set_collision_layer_value(GLOBAL.LOW_COLLISION, 1)
$ExplosionArea.set_collision_mask_value(GLOBAL.LOW_COLLISION, 1)
# --- Signals ---
func _on_VisibilityNotifier2D_screen_exited():
self.queue_free()
func _on_Projectile_body_entered(body: PhysicsBody2D):
if armed:
for missile in bodies_in_area:
missile.queue_free()
self.queue_free()
func _on_ExplosionArea_body_entered(body: PhysicsBody2D):
if armed and body.get_node("Mask").highlighted == $Mask.highlighted:
bodies_in_area.push_front(body)
func _on_ExplosionArea_body_exited(body: PhysicsBody2D):
if armed:
bodies_in_area.erase(body)