Randoloot/scripts/planets/surface_world.gd
2026-10-18 08:43:54 +02:00

155 lines
7.1 KiB
GDScript

extends Node2D
const GENERATOR_ATLAS_PATH := preload("res://scripts/planets/surface_details.gd").ATLAS_PATH
const BUILDING_SCALE := preload("res://scripts/planets/surface_scenery.gd").BUILDING_SCALE
const GENERATOR := preload("res://scripts/planets/surface_generator.gd")
var data: Dictionary
var terrain: ImageTexture
var _nature: Array[AtlasTexture] = []
var _tree: Texture2D
var _mountain: Texture2D
var _poi_sprites: Dictionary = {}
var _poi_labels: Dictionary = {}
var _event_nodes: Array[Dictionary] = []
func _ready() -> void:
texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR_WITH_MIPMAPS
terrain = GENERATOR.terrain_texture(data)
var ground := Sprite2D.new()
ground.name = "Terrain"
ground.texture = data.height_texture
ground.scale = Vector2.ONE * GENERATOR.WORLD_SIZE / ground.texture.get_width()
ground.z_index = -5
var material := ShaderMaterial.new()
material.shader = preload("res://resources/effects/planet_terrain.gdshader")
material.set_shader_parameter("height_map",data.height_texture)
material.set_shader_parameter("grass_detail",preload("res://assets/planets/grass.png"))
for kind in ["soil","rock","sand","moss"]:
material.set_shader_parameter(kind+"_detail",load("res://assets/planets/terrain/%s.png" % kind))
material.set_shader_parameter("biome_kind",int(data.landscape.index))
for key in ["low","high","sand","rock"]:
material.set_shader_parameter(key+"_color",data.landscape[key])
material.set_shader_parameter("climate",float(data.profile.temperature))
material.set_shader_parameter("seed_offset",float(posmod(int(data.seed),10000)))
ground.material = material
add_child(ground)
var atlas: Texture2D = load(GENERATOR_ATLAS_PATH)
var atlas_scale := Vector2(atlas.get_size()) / 1280.0
# The painted sheet has uneven transparent gutters; avoid clipping canopies.
var rows := [Vector2(0,360), Vector2(360,280), Vector2(640,310), Vector2(950,330)]
for index in 16:
var tile := AtlasTexture.new()
tile.atlas = atlas
var band: Vector2 = rows[index / 4]
var region := Rect2(float(index % 4)*320.0, band.x, 320.0, band.y)
if index == 12:
region = Rect2(0,950,365,330)
elif index == 13:
region = Rect2(370,950,270,330)
tile.region = Rect2(region.position*atlas_scale, region.size*atlas_scale)
tile.filter_clip = true
_nature.append(tile)
_tree = load("res://assets/planets/tree.png")
_mountain = load("res://assets/planets/mountain.png")
for poi in data.pois:
var sprite := Sprite2D.new()
sprite.texture = load("res://assets/planets/%s.png" % ("ruins" if poi.kind == "ruins" else "mine")) if poi.kind != "deposit" else load("res://assets/icons/resources/titanium.png")
sprite.position = poi.position
sprite.scale = Vector2.ONE * (125.0*BUILDING_SCALE if poi.kind != "deposit" else 60.0) / maxf(sprite.texture.get_width(), sprite.texture.get_height())
sprite.z_index = 10
add_child(sprite)
_poi_sprites[poi.id] = sprite
var label := Label.new()
label.position = poi.position + Vector2(-120, 46)
label.size.x = 240
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
label.add_theme_font_size_override("font_size", 13)
label.add_theme_color_override("font_color", Color("f0d5a1"))
label.add_theme_color_override("font_shadow_color", Color("061310"))
label.add_theme_constant_override("shadow_outline_size", 5)
label.z_index = 15
add_child(label)
_poi_labels[poi.id] = label
for landmark in data.get("landmarks", []):
var prop := Sprite2D.new()
prop.name = str(landmark.kind).to_pascal_case()
prop.texture = load("res://assets/planets/landmarks/%s.png" % landmark.kind)
prop.position = landmark.position
prop.rotation = landmark.rotation
prop.scale = Vector2.ONE * float(landmark.size) / maxf(prop.texture.get_width(), prop.texture.get_height())
prop.z_index = -2
add_child(prop)
for structure in data.structures:
var prop := Sprite2D.new()
prop.name = str(structure.kind).to_pascal_case()
prop.texture = load("res://assets/planets/props/%s.png" % structure.kind)
prop.position = structure.position
prop.rotation = structure.rotation
prop.scale = Vector2.ONE * float(structure.size) / maxf(prop.texture.get_width(),prop.texture.get_height())
prop.z_index = 4
add_child(prop)
for index in data.events.size():
var event: Dictionary = data.events[index]
var marker := Label.new()
marker.name = "EventMarker%d" % index
marker.text = "?"
marker.position = event.position+Vector2(-22,-28)
marker.size = Vector2(44,55)
marker.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
marker.add_theme_font_size_override("font_size",40)
marker.add_theme_color_override("font_color",Color("f8d685"))
marker.add_theme_color_override("font_outline_color",Color("17211b"))
marker.add_theme_constant_override("outline_size",7)
marker.z_index = 25
add_child(marker)
_event_nodes.append({"marker":marker})
refresh_pois(Vector2.ZERO)
func refresh_pois(lander_position: Vector2) -> void:
for index in data.events.size():
var event: Dictionary = data.events[index]
if lander_position.distance_to(event.position) < 600:
event.discovered = true
var nodes: Dictionary = _event_nodes[index]
nodes.marker.visible = not event.complete
for poi in data.pois:
if lander_position.distance_to(poi.position) < 650:
poi.discovered = true
var sprite: Sprite2D = _poi_sprites[poi.id]
sprite.visible = bool(poi.discovered)
sprite.modulate = Color(0.5, 0.55, 0.5) if poi.complete else Color.WHITE
var label: Label = _poi_labels[poi.id]
label.visible = bool(poi.discovered)
var title: String = {"mine": "Opuszczona kopalnia", "ruins": "Starożytne ruiny", "deposit": "Złoże minerałów"}[poi.kind]
label.text = title + (" · zbadano" if poi.complete else ("\n[F] Zbadaj" if lander_position.distance_to(poi.position) <= 150 else ""))
func _draw() -> void:
if terrain == null:
return
for detail in data.get("details", []):
var shade := float(detail.shade)
_draw_prop(_nature[int(detail.variant)], detail.position, detail.size, detail.rotation, Color(shade,shade,shade))
for mountain in data.mountains:
_draw_prop(_mountain, mountain.position, mountain.size, mountain.rotation, Color.WHITE)
for rock in data.rocks:
_draw_prop(_nature[int(rock.get("variant",4))],rock.position,rock.size,rock.rotation,Color.WHITE)
for tree in data.trees:
var shade := float(tree.shade)
var color: Color = Color(shade,shade,shade)*data.landscape.trees
if int(data.profile.temperature) < -10:
color = color.lerp(Color("d1e1da"), 0.4)
elif int(data.profile.temperature) > 40:
color = color.lerp(Color("c6a86b"), 0.28)
var variant := int(tree.get("variant", -1))
_draw_prop(_tree if variant < 0 else _nature[variant], tree.position, tree.size, tree.rotation, color)
# Small landing beacon.
draw_circle(Vector2.ZERO, 50, Color(0.5, 0.85, 0.8, 0.12))
draw_arc(Vector2.ZERO, 48, 0, TAU, 48, Color("8cd9c2"), 2, true)
func _draw_prop(texture: Texture2D, point: Vector2, width: float, angle: float, color: Color) -> void:
draw_set_transform(point, angle)
var size := Vector2(width, width*float(texture.get_height())/float(texture.get_width()))
draw_texture_rect(texture, Rect2(-size*0.5, size), false, color)
draw_set_transform(Vector2.ZERO)