Efejty swietlen gwiazdy

This commit is contained in:
Tomasz Boruc 2026-10-11 15:51:58 +02:00
parent dc9f97d1cc
commit b5fdf0cecc
9 changed files with 129 additions and 0 deletions

View File

@ -6,6 +6,7 @@ func _ready() -> void:
enemy = get_parent() as CharacterBody2D
top_level = true
z_index = 30
light_mask = 4
_update_position()
func _process(_delta: float) -> void:

View File

@ -56,6 +56,7 @@ func configure(player: CharacterBody2D, ship_texture: Texture2D) -> void:
var visual_size := get_visual_size()
_sprite.scale = Vector2.ONE * (visual_size / largest_dimension)
_sprite.modulate = Color("ffc785") if loot_tier == 1 else Color.WHITE
preload("res://scripts/game/ship_shadow.gd").attach_to(_sprite)
func get_visual_size() -> float:
return 112.0 if loot_tier == 2 else (68.0 if loot_tier == 1 else 56.0)

View File

@ -100,6 +100,7 @@ func _ready() -> void:
_sprite.texture = ship_texture
var largest_dimension := maxf(ship_texture.get_width(), ship_texture.get_height())
_sprite.scale = Vector2.ONE * (64.0 / largest_dimension)
preload("res://scripts/game/ship_shadow.gd").attach_to(_sprite)
# Inventory children have already applied the restored equipment bonuses.
hull = max_hull
shields = max_shields

View File

@ -0,0 +1,54 @@
extends RefCounted
# Cache one simplified silhouette per texture, shared by all ships of that type.
static var _silhouettes: Dictionary = {}
static func attach_to(sprite: Sprite2D) -> void:
if sprite.texture == null:
return
sprite.light_mask = 2
if sprite.has_node("ShipShadow"):
return
var texture := sprite.texture
var key := texture.get_instance_id()
if not _silhouettes.has(key):
var image := texture.get_image()
if image == null or image.is_empty():
return
if image.is_compressed():
image.decompress()
var original_size := Vector2(image.get_size())
var factor := minf(1.0, 128.0 / maxf(original_size.x, original_size.y))
image.resize(maxi(1, roundi(original_size.x * factor)), maxi(1, roundi(original_size.y * factor)), Image.INTERPOLATE_BILINEAR)
var bitmap := BitMap.new()
bitmap.create_from_image_alpha(image, 0.25)
var polygons := bitmap.opaque_to_polygons(Rect2i(Vector2i.ZERO, image.get_size()), 1.5)
var silhouette := PackedVector2Array()
var largest_area := 0.0
for polygon in polygons:
var area := _polygon_area(polygon)
if area > largest_area:
largest_area = area
silhouette = polygon
var image_scale := original_size / Vector2(image.get_size())
for index in silhouette.size():
silhouette[index] = silhouette[index] * image_scale - original_size * 0.5
_silhouettes[key] = silhouette
var points: PackedVector2Array = _silhouettes[key]
if points.size() < 3:
return
var polygon := OccluderPolygon2D.new()
polygon.polygon = points
polygon.cull_mode = OccluderPolygon2D.CULL_DISABLED
var occluder := LightOccluder2D.new()
occluder.name = "ShipShadow"
occluder.occluder = polygon
occluder.occluder_light_mask = 1
occluder.show_behind_parent = true
sprite.add_child(occluder)
static func _polygon_area(points: PackedVector2Array) -> float:
var area := 0.0
for index in points.size():
area += points[index].cross(points[(index + 1) % points.size()])
return absf(area) * 0.5

View File

@ -0,0 +1 @@
uid://b2jj0dueysvnp

View File

@ -0,0 +1,53 @@
extends RefCounted
const LIGHT_RADIUS := 3400.0
const LIGHT_ENERGY := 0.28
const SHIP_LIGHT_ENERGY := 0.16
const LIGHT_COLOR := Color(1.0, 0.93, 0.82)
static func attach_to(star: Node2D) -> void:
var gradient := Gradient.new()
gradient.offsets = PackedFloat32Array([0.0, 0.25, 0.65, 1.0])
gradient.colors = PackedColorArray([Color.WHITE, Color(1, 1, 1, 0.9), Color(1, 1, 1, 0.5), Color(1, 1, 1, 0)])
var texture := GradientTexture2D.new()
texture.gradient = gradient
texture.width = 512
texture.height = 512
texture.fill = GradientTexture2D.FILL_RADIAL
texture.fill_from = Vector2(0.5, 0.5)
texture.fill_to = Vector2(0.5, 0.0)
var light := PointLight2D.new()
light.name = "StarLight"
light.texture = texture
light.texture_scale = LIGHT_RADIUS * 2.0 / texture.width
light.color = LIGHT_COLOR
light.energy = LIGHT_ENERGY
light.range_item_cull_mask = 1
light.shadow_enabled = true
light.shadow_item_cull_mask = 1
light.shadow_filter = Light2D.SHADOW_FILTER_PCF5
light.shadow_filter_smooth = 2.0
star.add_child(light)
# A separate mask lights hulls without their own silhouettes darkening them.
var hull_light := PointLight2D.new()
hull_light.name = "HullLight"
hull_light.texture = texture
hull_light.texture_scale = light.texture_scale
hull_light.color = LIGHT_COLOR
hull_light.energy = SHIP_LIGHT_ENERGY
hull_light.range_item_cull_mask = 2
star.add_child(hull_light)
var glow := Sprite2D.new()
glow.name = "StarGlow"
glow.texture = texture
glow.scale = Vector2.ONE * (float(star.get("radius")) * 5.0 / texture.width)
glow.modulate = Color(LIGHT_COLOR, 0.09)
glow.z_index = -1
var material := CanvasItemMaterial.new()
material.blend_mode = CanvasItemMaterial.BLEND_MODE_ADD
material.light_mode = CanvasItemMaterial.LIGHT_MODE_UNSHADED
glow.material = material
star.add_child(glow)

View File

@ -0,0 +1 @@
uid://kmnxv1hp273t

View File

@ -14,8 +14,15 @@ func _ready() -> void:
sprite.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR
var longest_side := maxf(body_texture.get_width(), body_texture.get_height())
sprite.scale = Vector2.ONE * (radius * 2.0 / longest_side)
if is_star:
var material := CanvasItemMaterial.new()
material.light_mode = CanvasItemMaterial.LIGHT_MODE_UNSHADED
sprite.material = material
add_child(sprite)
if is_star:
preload("res://scripts/game/star_lighting.gd").attach_to(self)
_label = Label.new()
_label.light_mask = 4
_label.position = Vector2(-160, radius + 14)
_label.size = Vector2(320, 54)
_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER

View File

@ -13,6 +13,12 @@ func _ready() -> void:
get_tree().current_scene = game
_freeze(game)
_assert_boss_and_health(game)
var star := game.get_node("CelestialBodies/CentralStar")
var star_light: PointLight2D = star.get_node("StarLight")
assert(star_light.shadow_enabled and star_light.energy < 0.5)
assert(star_light.position == Vector2.ZERO)
assert(star_light.shadow_filter == Light2D.SHADOW_FILTER_PCF5)
assert(star.get_node("HullLight").get("range_item_cull_mask") == 2)
assert(GameState.system_level == 1 and int(game.call("get_remaining_enemies")) == 5)
assert(not game.has_node("WeaponTestTarget"))
assert(game.get_node("CelestialBodies").get_child_count() >= 2)
@ -146,10 +152,14 @@ func _freeze(game: Node2D) -> void:
game.set_physics_process(false)
game.get_node("PlayerShip").set_physics_process(false)
game.get_node("PlayerShip/WeaponController").set_physics_process(false)
assert(game.get_node("PlayerShip/Sprite2D/ShipShadow") is LightOccluder2D)
for enemy in get_tree().get_nodes_in_group("enemies"):
if game.is_ancestor_of(enemy):
var data: Dictionary = game.get("system_data")
assert(enemy.get_node("Sprite2D").get("texture") == game.ENEMY_TEXTURES[int(data["enemy_texture_index"])])
var shadow: LightOccluder2D = enemy.get_node("Sprite2D/ShipShadow")
assert(shadow.occluder.polygon.size() >= 3)
assert(shadow.global_scale.is_equal_approx(enemy.get_node("Sprite2D").global_scale))
enemy.set_physics_process(false)
func _assert_boss_and_health(game: Node2D) -> void: