Nowe tła
This commit is contained in:
parent
d7581d2f70
commit
e857aa8181
23
assets/background/space/VARIANTS.md
Normal file
23
assets/background/space/VARIANTS.md
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# Space background variants
|
||||||
|
|
||||||
|
Generated with built-in imagegen. The original deep_space.png remains the first background. New artwork cycles through systems 2–6, then repeats every six systems. Native Parallax2D motion, dust and star layers are unchanged.
|
||||||
|
|
||||||
|
## teal_veil.png
|
||||||
|
|
||||||
|
Use case: stylized-concept. Final production landscape 3:2 background texture for a top-down space RPG, at least 1536 by 1024 pixels. Realistic painterly astronomical space art, extremely fine sharp dust filaments and delicate stars. Preserve dark near-black navy central negative space for readable spaceship combat. Rich detail at outer regions, restrained low-key luminosity, no overexposed masses, no planets, no ships, no text, no interface, no border. Entire image is deep space. Variant: turquoise veil. Vast elegant teal and cyan nebula curtains drifting diagonally from the lower left to the upper right, deep blue dark dust channels, a very small distant warm spiral galaxy near the upper left. Dense intricate wisps but broad dark center, subdued silver starlight.
|
||||||
|
|
||||||
|
## crimson_rift.png
|
||||||
|
|
||||||
|
Use case: stylized-concept. Final production landscape 3:2 background texture for a top-down space RPG, at least 1536 by 1024 pixels. Realistic painterly astronomical space art, extremely fine sharp dust filaments and delicate stars. Preserve dark near-black navy central negative space for readable spaceship combat. Rich detail at outer regions, restrained low-key luminosity, no overexposed masses, no planets, no ships, no text, no interface, no border. Entire image is deep space. Variant: crimson rift. Deep ruby and burgundy emission nebula filaments around a sweeping dark interstellar dust rift. Muted copper edges and faint magenta distant star clusters. A tiny faraway edge-on galaxy in one outer quadrant. Mysterious deep space, asymmetric painted composition, dark broad center, no giant bright object.
|
||||||
|
|
||||||
|
## amber_expanse.png
|
||||||
|
|
||||||
|
Use case: stylized-concept. Final production landscape 3:2 background texture for a top-down space RPG, at least 1536 by 1024 pixels. Realistic painterly astronomical space art, extremely fine sharp dust filaments and delicate stars. Preserve dark near-black navy central negative space for readable spaceship combat. Rich detail at outer regions, restrained low-key luminosity, no overexposed masses, no planets, no ships, no text, no interface, no border. Entire image is deep space. Variant: amber expanse. Immense fine warm gold and bronze interstellar clouds sweeping around a dark navy central void, delicate smoky copper filaments, subtle deep blue counterlight and sparse pale gold stars, a small distant galaxy embedded near the outer right edge. Atmospheric and ancient, luminosity restrained, richly layered natural astrophotographic structure.
|
||||||
|
|
||||||
|
## violet_spiral.png
|
||||||
|
|
||||||
|
Use case: stylized-concept. Final production landscape 3:2 background texture for a top-down space RPG, at least 1536 by 1024 pixels. Realistic painterly astronomical space art, extremely fine sharp dust filaments and delicate stars. Preserve dark near-black navy central negative space for readable spaceship combat. Rich detail at outer regions, restrained low-key luminosity, no overexposed masses, no planets, no ships, no text, no interface, no border. Entire image is deep space. Variant: violet spiral. A distant gently inclined spiral galaxy with violet and lilac arms in the far upper-right quadrant, moderate small size and dim warm center, vast muted plum and indigo wisps curving along the outer image edges, exceptionally fine cosmic dust lanes, soft blue distant star clusters. Majority central space remains dark, mysterious and spacious, no huge galactic core.
|
||||||
|
|
||||||
|
## frozen_void.png
|
||||||
|
|
||||||
|
Use case: stylized-concept. Final production landscape 3:2 background texture for a top-down space RPG, at least 1536 by 1024 pixels. Realistic painterly astronomical space art, extremely fine sharp dust filaments and delicate stars. Preserve dark near-black navy central negative space for readable spaceship combat. Rich detail at outer regions, restrained low-key luminosity, no overexposed masses, no planets, no ships, no text, no interface, no border. Entire image is deep space. Variant: frozen void. Vast nearly black deep intergalactic space, cold slate-blue and silver-white cirrus-like interstellar dust along the left and lower outer regions, very faint icy cyan tendrils, two tiny remote galaxies and sparse crisp distant stars. Quiet, austere and spacious. Broad clean near-black central combat area, high-detail subtle cloud structure, low saturation and low brightness.
|
||||||
BIN
assets/background/space/amber_expanse.png
Normal file
BIN
assets/background/space/amber_expanse.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 MiB |
40
assets/background/space/amber_expanse.png.import
Normal file
40
assets/background/space/amber_expanse.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ds3otmcvnigjl"
|
||||||
|
path="res://.godot/imported/amber_expanse.png-3f0d05b567168730e5a7f3165b1f792e.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/background/space/amber_expanse.png"
|
||||||
|
dest_files=["res://.godot/imported/amber_expanse.png-3f0d05b567168730e5a7f3165b1f792e.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/background/space/crimson_rift.png
Normal file
BIN
assets/background/space/crimson_rift.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
40
assets/background/space/crimson_rift.png.import
Normal file
40
assets/background/space/crimson_rift.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://4le8obqsnyls"
|
||||||
|
path="res://.godot/imported/crimson_rift.png-64a6106d291393c89fe92f833ccc307a.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/background/space/crimson_rift.png"
|
||||||
|
dest_files=["res://.godot/imported/crimson_rift.png-64a6106d291393c89fe92f833ccc307a.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/background/space/frozen_void.png
Normal file
BIN
assets/background/space/frozen_void.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.3 MiB |
40
assets/background/space/frozen_void.png.import
Normal file
40
assets/background/space/frozen_void.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ctuoqueipre6u"
|
||||||
|
path="res://.godot/imported/frozen_void.png-27db06ffcfc6a21d856449611e6a0f6a.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/background/space/frozen_void.png"
|
||||||
|
dest_files=["res://.godot/imported/frozen_void.png-27db06ffcfc6a21d856449611e6a0f6a.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/background/space/teal_veil.png
Normal file
BIN
assets/background/space/teal_veil.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
40
assets/background/space/teal_veil.png.import
Normal file
40
assets/background/space/teal_veil.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ca7inlb4051jg"
|
||||||
|
path="res://.godot/imported/teal_veil.png-c156d68322d84804e2034f3ec932d377.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/background/space/teal_veil.png"
|
||||||
|
dest_files=["res://.godot/imported/teal_veil.png-c156d68322d84804e2034f3ec932d377.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
BIN
assets/background/space/violet_spiral.png
Normal file
BIN
assets/background/space/violet_spiral.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
40
assets/background/space/violet_spiral.png.import
Normal file
40
assets/background/space/violet_spiral.png.import
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ba4150mb4y0ks"
|
||||||
|
path="res://.godot/imported/violet_spiral.png-353286ec4f5d83fdeddcc8a4d50b4cbc.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://assets/background/space/violet_spiral.png"
|
||||||
|
dest_files=["res://.godot/imported/violet_spiral.png-353286ec4f5d83fdeddcc8a4d50b4cbc.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=true
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
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
|
||||||
@ -242,7 +242,7 @@ func _layout_debug() -> void:
|
|||||||
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
|
var top := _captain_panel.position.y + _captain_panel.size.y + 6.0
|
||||||
if is_instance_valid(_passive_skills):
|
if is_instance_valid(_passive_skills):
|
||||||
_passive_skills.position = Vector2(_captain_panel.position.x, top)
|
_passive_skills.position = Vector2(_captain_panel.position.x, top)
|
||||||
_passive_skills.size = Vector2(320, _passive_skills.get_combined_minimum_size().y)
|
_passive_skills.size = Vector2(36, _passive_skills.get_combined_minimum_size().y)
|
||||||
if _passive_skills.visible:
|
if _passive_skills.visible:
|
||||||
top += _passive_skills.size.y + 8.0
|
top += _passive_skills.size.y + 8.0
|
||||||
debug_toggle.position = Vector2(12, top)
|
debug_toggle.position = Vector2(12, top)
|
||||||
@ -463,53 +463,13 @@ func _refresh_passive_skills() -> void:
|
|||||||
var rank := GameState.captain.get_skill_rank(skill)
|
var rank := GameState.captain.get_skill_rank(skill)
|
||||||
if rank <= 0 or bool(catalog.DATA[skill]["active"]):
|
if rank <= 0 or bool(catalog.DATA[skill]["active"]):
|
||||||
continue
|
continue
|
||||||
var accent := Color(catalog.DATA[skill]["color"])
|
|
||||||
var card := PanelContainer.new()
|
|
||||||
card.name = skill
|
|
||||||
card.custom_minimum_size = Vector2(320, 54)
|
|
||||||
card.tooltip_text = catalog.description(skill, rank)
|
|
||||||
var style := StyleBoxFlat.new()
|
|
||||||
style.bg_color = Color(0.025, 0.042, 0.064, 0.94)
|
|
||||||
style.border_color = accent.darkened(0.6)
|
|
||||||
style.set_border_width_all(1)
|
|
||||||
style.border_width_left = 2
|
|
||||||
style.set_corner_radius_all(7)
|
|
||||||
style.set_content_margin_all(8)
|
|
||||||
card.add_theme_stylebox_override("panel", style)
|
|
||||||
_passive_skills.add_child(card)
|
|
||||||
var row := HBoxContainer.new()
|
|
||||||
row.add_theme_constant_override("separation", 10)
|
|
||||||
card.add_child(row)
|
|
||||||
var icon := Button.new()
|
var icon := Button.new()
|
||||||
|
icon.name = skill
|
||||||
icon.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
|
icon.set_script(preload("res://scripts/ui/captain_skill_button.gd"))
|
||||||
icon.call("configure", catalog.icon(skill), accent)
|
icon.call("configure", catalog.icon(skill), Color(catalog.DATA[skill]["color"]))
|
||||||
icon.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
||||||
icon.disabled = true
|
icon.disabled = true
|
||||||
row.add_child(icon)
|
icon.mouse_default_cursor_shape = Control.CURSOR_HELP
|
||||||
var contents := VBoxContainer.new()
|
icon.tooltip_text = "%s · poziom %d / 3\n%s" % [catalog.DATA[skill]["name"], rank, catalog.description(skill, rank)]
|
||||||
contents.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
_passive_skills.add_child(icon)
|
||||||
contents.add_theme_constant_override("separation", 3)
|
|
||||||
row.add_child(contents)
|
|
||||||
var header := HBoxContainer.new()
|
|
||||||
contents.add_child(header)
|
|
||||||
var title := _passive_label(catalog.DATA[skill]["name"], 14, Color("dfedf4"))
|
|
||||||
title.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
|
||||||
header.add_child(title)
|
|
||||||
header.add_child(_passive_label("●".repeat(rank) + "○".repeat(3 - rank), 10, accent))
|
|
||||||
var value := roundi(GameState.captain.get_skill_bonus(skill) * 100)
|
|
||||||
var summary := ""
|
|
||||||
match skill:
|
|
||||||
"business_shark": summary = "−%d%% kosztów zakupów" % value
|
|
||||||
"efficient_magazine": summary = "−%d%% zużycia amunicji" % value
|
|
||||||
"miner": summary = "+%d surowca / asteroidę" % roundi(GameState.captain.get_skill_bonus(skill))
|
|
||||||
contents.add_child(_passive_label(summary, 12, accent))
|
|
||||||
_passive_skills.visible = _passive_skills.get_child_count() > 0
|
_passive_skills.visible = _passive_skills.get_child_count() > 0
|
||||||
_layout_debug.call_deferred()
|
_layout_debug.call_deferred()
|
||||||
|
|
||||||
func _passive_label(text: String, font_size: int, color: Color) -> Label:
|
|
||||||
var label := Label.new()
|
|
||||||
label.text = text
|
|
||||||
label.add_theme_font_override("font", ThemeDB.fallback_font)
|
|
||||||
label.add_theme_font_size_override("font_size", font_size)
|
|
||||||
label.add_theme_color_override("font_color", color)
|
|
||||||
return label
|
|
||||||
|
|||||||
@ -1,7 +1,14 @@
|
|||||||
extends Node2D
|
extends Node2D
|
||||||
|
|
||||||
const WORLD_SIZE := Vector2(5200.0, 3600.0)
|
const WORLD_SIZE := Vector2(5200.0, 3600.0)
|
||||||
const FAR_TEXTURE := preload("res://assets/background/space/deep_space.png")
|
const BACKGROUND_PATHS := [
|
||||||
|
"res://assets/background/space/deep_space.png",
|
||||||
|
"res://assets/background/space/teal_veil.png",
|
||||||
|
"res://assets/background/space/crimson_rift.png",
|
||||||
|
"res://assets/background/space/amber_expanse.png",
|
||||||
|
"res://assets/background/space/violet_spiral.png",
|
||||||
|
"res://assets/background/space/frozen_void.png",
|
||||||
|
]
|
||||||
const DUST_TEXTURE := preload("res://assets/background/space/nebula_dust.png")
|
const DUST_TEXTURE := preload("res://assets/background/space/nebula_dust.png")
|
||||||
const STAR_TILE := Vector2(2048.0, 1536.0)
|
const STAR_TILE := Vector2(2048.0, 1536.0)
|
||||||
|
|
||||||
@ -13,7 +20,9 @@ func _ready() -> void:
|
|||||||
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
|
||||||
var distant := _make_layer("DistantGalaxies", 0.04)
|
var distant := _make_layer("DistantGalaxies", 0.04)
|
||||||
_far_sprite = Sprite2D.new()
|
_far_sprite = Sprite2D.new()
|
||||||
_far_sprite.texture = FAR_TEXTURE
|
# Only the artwork changes between systems; parallax layers stay identical.
|
||||||
|
var background_index := posmod(GameState.system_level - 1, BACKGROUND_PATHS.size())
|
||||||
|
_far_sprite.texture = load(BACKGROUND_PATHS[background_index]) as Texture2D
|
||||||
_far_sprite.modulate = Color(0.8, 0.85, 0.95)
|
_far_sprite.modulate = Color(0.8, 0.85, 0.95)
|
||||||
distant.add_child(_far_sprite)
|
distant.add_child(_far_sprite)
|
||||||
_resize_background()
|
_resize_background()
|
||||||
@ -45,7 +54,7 @@ func _resize_background() -> void:
|
|||||||
# Native resolution at 720p; retain aspect ratio and cover camera travel.
|
# Native resolution at 720p; retain aspect ratio and cover camera travel.
|
||||||
_far_sprite.position = view_size * 0.5
|
_far_sprite.position = view_size * 0.5
|
||||||
var required := view_size + WORLD_SIZE * 0.04 + Vector2(32.0, 32.0)
|
var required := view_size + WORLD_SIZE * 0.04 + Vector2(32.0, 32.0)
|
||||||
var ratio := required / FAR_TEXTURE.get_size()
|
var ratio := required / _far_sprite.texture.get_size()
|
||||||
_far_sprite.scale = Vector2.ONE * maxf(1.0, maxf(ratio.x, ratio.y))
|
_far_sprite.scale = Vector2.ONE * maxf(1.0, maxf(ratio.x, ratio.y))
|
||||||
|
|
||||||
func _make_stars(layer_name: String, speed: float, count: int, seed_offset: int) -> void:
|
func _make_stars(layer_name: String, speed: float, count: int, seed_offset: int) -> void:
|
||||||
|
|||||||
@ -13,9 +13,9 @@ var max_range := 800.0
|
|||||||
var weapon_kind := ItemDefinition.WeaponKind.PLASMA
|
var weapon_kind := ItemDefinition.WeaponKind.PLASMA
|
||||||
var homing_target: Node2D
|
var homing_target: Node2D
|
||||||
var missile_homing := true
|
var missile_homing := true
|
||||||
var homing_turn_acceleration := 2.3
|
var homing_turn_acceleration := 5.0
|
||||||
var homing_max_turn_speed := 1.7
|
var homing_max_turn_speed := 3.0
|
||||||
var missile_steering_acceleration := 520.0
|
var missile_steering_acceleration := 1400.0
|
||||||
var target_acquisition_range := 360.0
|
var target_acquisition_range := 360.0
|
||||||
var seeker_arm_delay := 0.35
|
var seeker_arm_delay := 0.35
|
||||||
var _flight_velocity := Vector2.ZERO
|
var _flight_velocity := Vector2.ZERO
|
||||||
@ -83,7 +83,7 @@ func _physics_process(delta: float) -> void:
|
|||||||
PI
|
PI
|
||||||
)
|
)
|
||||||
desired_turn_velocity = clampf(
|
desired_turn_velocity = clampf(
|
||||||
angle_error * 2.0,
|
angle_error * 4.0,
|
||||||
-homing_max_turn_speed,
|
-homing_max_turn_speed,
|
||||||
homing_max_turn_speed
|
homing_max_turn_speed
|
||||||
)
|
)
|
||||||
|
|||||||
72
tests/abilities/missile_guidance_test.gd
Normal file
72
tests/abilities/missile_guidance_test.gd
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
extends Node2D
|
||||||
|
|
||||||
|
const PROJECTILE := preload("res://scenes/game/weapon_projectile.tscn")
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
seed(1234)
|
||||||
|
# Both stationary and crossing targets should be intercepted on the first pass.
|
||||||
|
for target_velocity in [Vector2.ZERO, Vector2(0, 55)]:
|
||||||
|
var target := CharacterBody2D.new()
|
||||||
|
target.position = Vector2(350, 70)
|
||||||
|
target.velocity = target_velocity
|
||||||
|
add_child(target)
|
||||||
|
var missile := _missile(target, 1200.0)
|
||||||
|
var closest := INF
|
||||||
|
for step in 240:
|
||||||
|
var previous: Vector2 = missile.position
|
||||||
|
target.position += target_velocity / 120.0
|
||||||
|
missile._physics_process(1.0 / 120.0)
|
||||||
|
var near := Geometry2D.get_closest_point_to_segment(target.position, previous, missile.position)
|
||||||
|
closest = minf(closest, near.distance_to(target.position))
|
||||||
|
assert(absf(missile._turn_velocity) <= missile.homing_max_turn_speed + 0.001)
|
||||||
|
if closest < 18.0 or missile.is_queued_for_deletion():
|
||||||
|
break
|
||||||
|
assert(closest < 18.0, "Missile missed a reachable intercept: %.2f" % closest)
|
||||||
|
missile.free()
|
||||||
|
target.free()
|
||||||
|
|
||||||
|
# Compare actual flight direction against the previous turn limits.
|
||||||
|
var side_target := Node2D.new()
|
||||||
|
side_target.position = Vector2(100, 200)
|
||||||
|
add_child(side_target)
|
||||||
|
var faster := _missile(side_target, 600.0)
|
||||||
|
var previous := _missile(side_target, 600.0)
|
||||||
|
previous.homing_turn_acceleration = 2.3
|
||||||
|
previous.homing_max_turn_speed = 1.7
|
||||||
|
previous.missile_steering_acceleration = 520.0
|
||||||
|
for step in 48:
|
||||||
|
faster._physics_process(1.0 / 120.0)
|
||||||
|
previous._physics_process(1.0 / 120.0)
|
||||||
|
assert(faster._heading > previous._heading * 1.5)
|
||||||
|
assert(faster._flight_velocity.angle() > previous._flight_velocity.angle() * 1.5)
|
||||||
|
assert(faster.homing_target == side_target)
|
||||||
|
faster.free()
|
||||||
|
previous.free()
|
||||||
|
side_target.free()
|
||||||
|
|
||||||
|
# Preserve the original pursuit behavior beyond acquisition range.
|
||||||
|
var far_target := Node2D.new()
|
||||||
|
far_target.position = Vector2(5000, 0)
|
||||||
|
far_target.add_to_group("enemies")
|
||||||
|
add_child(far_target)
|
||||||
|
var limited := _missile(far_target, 200.0)
|
||||||
|
limited._has_locked_target = true
|
||||||
|
for step in 120:
|
||||||
|
limited._physics_process(1.0 / 120.0)
|
||||||
|
if limited.is_queued_for_deletion():
|
||||||
|
break
|
||||||
|
assert(not limited.is_queued_for_deletion() and limited.homing_target == far_target)
|
||||||
|
assert(limited._has_locked_target)
|
||||||
|
limited.free()
|
||||||
|
far_target.free()
|
||||||
|
print("MISSILE_GUIDANCE_TEST: PASS (stationary and moving intercepts, faster heading and actual flight turn, original target pursuit)")
|
||||||
|
get_tree().quit()
|
||||||
|
|
||||||
|
func _missile(target: Node2D, flight_range: float) -> Area2D:
|
||||||
|
var missile := PROJECTILE.instantiate() as Area2D
|
||||||
|
missile.configure(Vector2.ZERO, Vector2.RIGHT, ItemDefinition.WeaponKind.MISSILE, 400.0, 10.0, flight_range, target)
|
||||||
|
missile.collision_mask = 0
|
||||||
|
add_child(missile)
|
||||||
|
missile.set_physics_process(false)
|
||||||
|
missile.set_process(false)
|
||||||
|
return missile
|
||||||
1
tests/abilities/missile_guidance_test.gd.uid
Normal file
1
tests/abilities/missile_guidance_test.gd.uid
Normal file
@ -0,0 +1 @@
|
|||||||
|
uid://2y4073uore6t
|
||||||
6
tests/abilities/missile_guidance_test.tscn
Normal file
6
tests/abilities/missile_guidance_test.tscn
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://tests/abilities/missile_guidance_test.gd" id="1"]
|
||||||
|
|
||||||
|
[node name="MissileGuidanceTest" type="Node2D"]
|
||||||
|
script = ExtResource("1")
|
||||||
Loading…
x
Reference in New Issue
Block a user