Merge branches 'main' and 'main' of https://git.ranaze.com/null/promiscuity
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 45s
Deploy Promiscuity Inventory API / deploy (push) Successful in 45s
Deploy Promiscuity Locations API / deploy (push) Successful in 45s
k8s smoke test / test (push) Successful in 8s
Deploy Promiscuity Auth API / deploy (push) Successful in 46s
Deploy Promiscuity Character API / deploy (push) Successful in 45s
Deploy Promiscuity Inventory API / deploy (push) Successful in 45s
Deploy Promiscuity Locations API / deploy (push) Successful in 45s
k8s smoke test / test (push) Successful in 8s
# Conflicts: # game/scenes/Levels/level.tscn
This commit is contained in:
+50
-25
@@ -13,10 +13,12 @@ var time := 0.0
|
||||
@onready var _player: Node = $Player
|
||||
@onready var _quest_text: RichTextLabel = $PhoneUI/Control/PhoneFrame/QuestText
|
||||
|
||||
const FIRST_QUEST_ID := "first_drive"
|
||||
const FIRST_QUEST := {
|
||||
"id": FIRST_QUEST_ID,
|
||||
"title": "RepoBot's First Task",
|
||||
const FIRST_QUEST_ID := "first_drive"
|
||||
const QUEST_PROMPT_META_PREFIX := "quest_intro_prompt_shown_"
|
||||
const SPAWN_DIALOG_META_KEY := "level_spawn_dialog_shown"
|
||||
const FIRST_QUEST := {
|
||||
"id": FIRST_QUEST_ID,
|
||||
"title": "RepoBot's First Task",
|
||||
"description": "Get familiar with movement and vehicles.",
|
||||
"steps": [
|
||||
{
|
||||
@@ -32,16 +34,17 @@ const FIRST_QUEST := {
|
||||
],
|
||||
}
|
||||
|
||||
func _ready() -> void:
|
||||
_setup_quests()
|
||||
if show_spawn_dialog and DialogSystem and DialogSystem.has_method("show_text"):
|
||||
await get_tree().process_frame
|
||||
DialogSystem.show_text(spawn_dialog_text)
|
||||
if spawn_dialog_auto_close_seconds > 0.0:
|
||||
await get_tree().create_timer(spawn_dialog_auto_close_seconds).timeout
|
||||
if DialogSystem and DialogSystem.has_method("close_if_text"):
|
||||
DialogSystem.close_if_text(spawn_dialog_text)
|
||||
_show_quest_intro_dialog()
|
||||
func _ready() -> void:
|
||||
_setup_quests()
|
||||
if _should_show_spawn_dialog() and DialogSystem and DialogSystem.has_method("show_text"):
|
||||
await get_tree().process_frame
|
||||
DialogSystem.show_text(spawn_dialog_text)
|
||||
_mark_spawn_dialog_shown()
|
||||
if spawn_dialog_auto_close_seconds > 0.0:
|
||||
await get_tree().create_timer(spawn_dialog_auto_close_seconds).timeout
|
||||
if DialogSystem and DialogSystem.has_method("close_if_text"):
|
||||
DialogSystem.close_if_text(spawn_dialog_text)
|
||||
_show_quest_intro_dialog()
|
||||
|
||||
func _process(delta):
|
||||
time = fmod((time + delta), day_length)
|
||||
@@ -94,14 +97,36 @@ func _refresh_quest_ui() -> void:
|
||||
_quest_text.text = "[b]%s[/b]\nStep %d/%d\n%s" % [title, step_index + 1, total_steps, step_text]
|
||||
|
||||
|
||||
func _show_quest_intro_dialog() -> void:
|
||||
if QuestManager == null:
|
||||
return
|
||||
var state: Dictionary = QuestManager.get_active_quest_state()
|
||||
if not bool(state.get("active", false)) or bool(state.get("completed", false)):
|
||||
return
|
||||
var step_text := String(state.get("current_step_text", ""))
|
||||
if step_text.is_empty():
|
||||
return
|
||||
if DialogSystem and DialogSystem.has_method("show_text"):
|
||||
DialogSystem.show_text("RepoBot: New task assigned.\n\n%s" % step_text)
|
||||
func _show_quest_intro_dialog() -> void:
|
||||
if QuestManager == null:
|
||||
return
|
||||
var state: Dictionary = QuestManager.get_active_quest_state()
|
||||
if not bool(state.get("active", false)) or bool(state.get("completed", false)):
|
||||
return
|
||||
var quest_id := String(state.get("quest_id", "")).strip_edges()
|
||||
var step_id := String(state.get("current_step_id", "")).strip_edges()
|
||||
var step_text := String(state.get("current_step_text", ""))
|
||||
if quest_id.is_empty() or step_id.is_empty() or step_text.is_empty():
|
||||
return
|
||||
var prompt_key := "%s%s_%s" % [QUEST_PROMPT_META_PREFIX, quest_id, step_id]
|
||||
if QuestManager.has_meta(prompt_key) and bool(QuestManager.get_meta(prompt_key)):
|
||||
return
|
||||
if DialogSystem and DialogSystem.has_method("show_text"):
|
||||
DialogSystem.show_text("RepoBot: New task assigned.\n\n%s" % step_text)
|
||||
QuestManager.set_meta(prompt_key, true)
|
||||
|
||||
|
||||
func _should_show_spawn_dialog() -> bool:
|
||||
if not show_spawn_dialog:
|
||||
return false
|
||||
if QuestManager == null:
|
||||
return true
|
||||
if not QuestManager.has_meta(SPAWN_DIALOG_META_KEY):
|
||||
return true
|
||||
return not bool(QuestManager.get_meta(SPAWN_DIALOG_META_KEY))
|
||||
|
||||
|
||||
func _mark_spawn_dialog_shown() -> void:
|
||||
if QuestManager == null:
|
||||
return
|
||||
QuestManager.set_meta(SPAWN_DIALOG_META_KEY, true)
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
[ext_resource type="PackedScene" uid="uid://bnqaqbgynoyys" path="res://assets/models/TestCharAnimated.glb" id="5_fi66n"]
|
||||
[ext_resource type="Script" uid="uid://bk53njt7i3kmv" path="res://scenes/Interaction/dialog_trigger_area.gd" id="6_dialog"]
|
||||
[ext_resource type="Script" uid="uid://cshtdpjp4xy2f" path="res://scenes/Quests/quest_trigger_area.gd" id="7_qtrigger"]
|
||||
[ext_resource type="PackedScene" path="res://scenes/Interaction/prototype_gateway.tscn" id="8_teleporter"]
|
||||
[ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="9_ground_mat"]
|
||||
[ext_resource type="Shader" uid="uid://bi3o8elbtqoni" path="res://addons/simplegrasstextured/shaders/grass.gdshader" id="9_43ksg"]
|
||||
[ext_resource type="Texture2D" uid="uid://c4ggdp0kg5wjk" path="res://addons/simplegrasstextured/textures/grassbushcc008.png" id="10_loupo"]
|
||||
[ext_resource type="Script" uid="uid://2juaclm8gc1n" path="res://addons/simplegrasstextured/grass.gd" id="11_1meta"]
|
||||
@@ -276,6 +278,7 @@ height = 6.0
|
||||
size = Vector3(1080, 2, 1080)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_w7c3h"]
|
||||
material = ExtResource("9_ground_mat")
|
||||
size = Vector3(1080, 2, 1080)
|
||||
|
||||
[sub_resource type="ShaderMaterial" id="ShaderMaterial_i35yb"]
|
||||
@@ -564,6 +567,10 @@ scroll_active = false
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_a4mo8")
|
||||
|
||||
[node name="LevelExitTeleporter" parent="." instance=ExtResource("8_teleporter")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5.5, 0, 0)
|
||||
target_scene_path = "res://scenes/Levels/transportation_level.tscn"
|
||||
|
||||
[connection signal="pressed" from="Menu/Control/VBoxContainer/ContinueButton" to="Menu" method="_on_continue_button_pressed"]
|
||||
[connection signal="pressed" from="Menu/Control/VBoxContainer/MainMenuButton" to="Menu" method="_on_main_menu_button_pressed"]
|
||||
[connection signal="pressed" from="Menu/Control/VBoxContainer/QuitButton" to="Menu" method="_on_quit_button_pressed"]
|
||||
|
||||
@@ -1,15 +1,332 @@
|
||||
extends Node3D
|
||||
|
||||
@export var tile_size := 4.0
|
||||
const CHARACTER_API_URL := "https://pchar.ranaze.com/api/Characters"
|
||||
|
||||
@export var tile_size := 16.0
|
||||
@export var block_height := 1.0
|
||||
@export_range(1, 8, 1) var tile_radius := 3
|
||||
@export var tracked_node_path: NodePath
|
||||
@export var player_spawn_height := 2.0
|
||||
@export var border_color: Color = Color(0.05, 0.05, 0.05, 1.0)
|
||||
@export var border_height_bias := 0.005
|
||||
@export var show_tile_labels := true
|
||||
@export var tile_label_height := 0.01
|
||||
@export var tile_label_color: Color = Color(1, 1, 1, 1)
|
||||
|
||||
@onready var _block: MeshInstance3D = $TerrainBlock
|
||||
@onready var _camera: Camera3D = $Camera3D
|
||||
@onready var _player: RigidBody3D = $Player
|
||||
@onready var _camera: Camera3D = $Player/Camera3D
|
||||
|
||||
var _center_coord := Vector2i.ZERO
|
||||
var _tiles_root: Node3D
|
||||
var _tracked_node: Node3D
|
||||
var _tile_nodes: Dictionary = {}
|
||||
var _camera_start_offset := Vector3(0.0, 6.0, 10.0)
|
||||
var _border_material: StandardMaterial3D
|
||||
var _known_locations: Dictionary = {}
|
||||
var _locations_loaded := false
|
||||
var _character_id := ""
|
||||
var _persisted_coord := Vector2i.ZERO
|
||||
var _coord_sync_in_flight := false
|
||||
var _queued_coord_sync: Variant = null
|
||||
var _locations_refresh_in_flight := false
|
||||
var _queued_locations_refresh := false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var coord := SelectedCharacter.get_coord()
|
||||
var block_pos := Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size)
|
||||
_block.position = block_pos
|
||||
_block.scale = Vector3(tile_size, block_height, tile_size)
|
||||
_tiles_root = Node3D.new()
|
||||
_tiles_root.name = "GeneratedTiles"
|
||||
add_child(_tiles_root)
|
||||
|
||||
if _camera:
|
||||
_camera.look_at(block_pos, Vector3.UP)
|
||||
_camera_start_offset = _camera.position
|
||||
|
||||
_tracked_node = get_node_or_null(tracked_node_path) as Node3D
|
||||
if _tracked_node == null:
|
||||
_tracked_node = _player
|
||||
|
||||
var start_coord := SelectedCharacter.get_coord()
|
||||
_center_coord = Vector2i(roundi(start_coord.x), roundi(start_coord.y))
|
||||
_persisted_coord = _center_coord
|
||||
_character_id = String(SelectedCharacter.character.get("id", SelectedCharacter.character.get("Id", ""))).strip_edges()
|
||||
|
||||
_block.visible = false
|
||||
await _load_existing_locations()
|
||||
_ensure_selected_location_exists(_center_coord)
|
||||
_rebuild_tiles(_center_coord)
|
||||
_move_player_to_coord(_center_coord)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if not _locations_loaded:
|
||||
return
|
||||
var target_world_pos := _get_stream_position()
|
||||
var target_coord := _world_to_coord(target_world_pos)
|
||||
if target_coord == _center_coord:
|
||||
return
|
||||
_center_coord = target_coord
|
||||
_queue_coord_sync(_center_coord)
|
||||
_queue_locations_refresh()
|
||||
|
||||
|
||||
func _get_stream_position() -> Vector3:
|
||||
if _tracked_node:
|
||||
return _tracked_node.global_position
|
||||
return _coord_to_world(_center_coord)
|
||||
|
||||
|
||||
func _world_to_coord(world_pos: Vector3) -> Vector2i:
|
||||
return Vector2i(
|
||||
roundi(world_pos.x / tile_size),
|
||||
roundi(world_pos.z / tile_size)
|
||||
)
|
||||
|
||||
|
||||
func _coord_to_world(coord: Vector2i) -> Vector3:
|
||||
return Vector3(coord.x * tile_size, block_height * 0.5, coord.y * tile_size)
|
||||
|
||||
|
||||
func _move_player_to_coord(coord: Vector2i) -> void:
|
||||
if _player == null:
|
||||
return
|
||||
_player.global_position = Vector3(coord.x * tile_size, player_spawn_height, coord.y * tile_size)
|
||||
_player.linear_velocity = Vector3.ZERO
|
||||
_player.angular_velocity = Vector3.ZERO
|
||||
|
||||
|
||||
func _rebuild_tiles(center: Vector2i) -> void:
|
||||
var wanted_keys: Dictionary = {}
|
||||
for x in range(center.x - tile_radius, center.x + tile_radius + 1):
|
||||
for y in range(center.y - tile_radius, center.y + tile_radius + 1):
|
||||
var coord := Vector2i(x, y)
|
||||
if not _known_locations.has(coord):
|
||||
continue
|
||||
wanted_keys[coord] = true
|
||||
if _tile_nodes.has(coord):
|
||||
continue
|
||||
_spawn_tile(coord, String(_known_locations[coord]))
|
||||
|
||||
for key in _tile_nodes.keys():
|
||||
if wanted_keys.has(key):
|
||||
continue
|
||||
var tile_node := _tile_nodes[key] as Node3D
|
||||
if tile_node:
|
||||
tile_node.queue_free()
|
||||
_tile_nodes.erase(key)
|
||||
|
||||
|
||||
func _spawn_tile(coord: Vector2i, location_name: String) -> void:
|
||||
var tile_root := Node3D.new()
|
||||
tile_root.name = "Tile_%d_%d" % [coord.x, coord.y]
|
||||
tile_root.position = _coord_to_world(coord)
|
||||
_tiles_root.add_child(tile_root)
|
||||
|
||||
var tile_body := StaticBody3D.new()
|
||||
tile_body.name = "TileBody"
|
||||
tile_body.scale = Vector3(tile_size, block_height, tile_size)
|
||||
tile_root.add_child(tile_body)
|
||||
|
||||
var collision_shape := CollisionShape3D.new()
|
||||
collision_shape.name = "CollisionShape3D"
|
||||
collision_shape.shape = BoxShape3D.new()
|
||||
tile_body.add_child(collision_shape)
|
||||
|
||||
var tile := _block.duplicate() as MeshInstance3D
|
||||
tile.name = "TileMesh"
|
||||
tile.visible = true
|
||||
tile_body.add_child(tile)
|
||||
|
||||
tile.add_child(_create_tile_border())
|
||||
if show_tile_labels:
|
||||
tile_root.add_child(_create_tile_label(location_name))
|
||||
|
||||
_tile_nodes[coord] = tile_root
|
||||
|
||||
|
||||
func _create_tile_border() -> MeshInstance3D:
|
||||
var top_y := 0.5 + border_height_bias
|
||||
var corners := [
|
||||
Vector3(-0.5, top_y, -0.5),
|
||||
Vector3(0.5, top_y, -0.5),
|
||||
Vector3(0.5, top_y, 0.5),
|
||||
Vector3(-0.5, top_y, 0.5),
|
||||
]
|
||||
|
||||
var border_mesh := ImmediateMesh.new()
|
||||
border_mesh.surface_begin(Mesh.PRIMITIVE_LINES, _get_border_material())
|
||||
for idx in range(corners.size()):
|
||||
var current: Vector3 = corners[idx]
|
||||
var next: Vector3 = corners[(idx + 1) % corners.size()]
|
||||
border_mesh.surface_add_vertex(current)
|
||||
border_mesh.surface_add_vertex(next)
|
||||
border_mesh.surface_end()
|
||||
|
||||
var border := MeshInstance3D.new()
|
||||
border.name = "TileBorder"
|
||||
border.mesh = border_mesh
|
||||
return border
|
||||
|
||||
|
||||
func _get_border_material() -> StandardMaterial3D:
|
||||
if _border_material:
|
||||
return _border_material
|
||||
|
||||
_border_material = StandardMaterial3D.new()
|
||||
_border_material.albedo_color = border_color
|
||||
_border_material.shading_mode = BaseMaterial3D.SHADING_MODE_UNSHADED
|
||||
_border_material.disable_receive_shadows = true
|
||||
_border_material.no_depth_test = true
|
||||
return _border_material
|
||||
|
||||
|
||||
func _create_tile_label(location_name: String) -> Label3D:
|
||||
var label := Label3D.new()
|
||||
label.name = "LocationNameLabel"
|
||||
label.text = location_name
|
||||
label.position = Vector3(0.0, (block_height * 0.5) + border_height_bias + tile_label_height, 0.0)
|
||||
label.rotation_degrees = Vector3(-90.0, 0.0, 0.0)
|
||||
label.billboard = BaseMaterial3D.BILLBOARD_DISABLED
|
||||
label.modulate = tile_label_color
|
||||
label.pixel_size = 0.01
|
||||
label.outline_size = 12
|
||||
label.no_depth_test = false
|
||||
return label
|
||||
|
||||
|
||||
func _ensure_selected_location_exists(coord: Vector2i) -> void:
|
||||
if _known_locations.has(coord):
|
||||
return
|
||||
_known_locations[coord] = _selected_location_name(coord)
|
||||
|
||||
|
||||
func _selected_location_name(coord: Vector2i) -> String:
|
||||
var selected_name := String(SelectedCharacter.character.get("locationName", "")).strip_edges()
|
||||
if not selected_name.is_empty():
|
||||
return selected_name
|
||||
var character_name := String(SelectedCharacter.character.get("name", "")).strip_edges()
|
||||
if not character_name.is_empty():
|
||||
return "%s's Location" % character_name
|
||||
return "Location %d,%d" % [coord.x, coord.y]
|
||||
|
||||
|
||||
func _load_existing_locations() -> void:
|
||||
_locations_refresh_in_flight = true
|
||||
_locations_loaded = false
|
||||
_known_locations.clear()
|
||||
|
||||
if _character_id.is_empty():
|
||||
push_warning("Selected character is missing an id; cannot load visible locations.")
|
||||
_locations_loaded = true
|
||||
return
|
||||
|
||||
var request := HTTPRequest.new()
|
||||
add_child(request)
|
||||
|
||||
var headers := PackedStringArray()
|
||||
if not AuthState.access_token.is_empty():
|
||||
headers.append("Authorization: Bearer %s" % AuthState.access_token)
|
||||
|
||||
var err := request.request("%s/%s/visible-locations" % [CHARACTER_API_URL, _character_id], headers, HTTPClient.METHOD_GET)
|
||||
if err != OK:
|
||||
push_warning("Failed to request visible locations: %s" % err)
|
||||
request.queue_free()
|
||||
_locations_loaded = true
|
||||
return
|
||||
|
||||
var result: Array = await request.request_completed
|
||||
request.queue_free()
|
||||
|
||||
var result_code: int = result[0]
|
||||
var response_code: int = result[1]
|
||||
var response_body: String = result[3].get_string_from_utf8()
|
||||
if result_code != HTTPRequest.RESULT_SUCCESS or response_code < 200 or response_code >= 300:
|
||||
push_warning("Failed to load visible locations (%s/%s): %s" % [result_code, response_code, response_body])
|
||||
_locations_loaded = true
|
||||
return
|
||||
|
||||
var parsed: Variant = JSON.parse_string(response_body)
|
||||
if typeof(parsed) != TYPE_ARRAY:
|
||||
push_warning("Visible locations response was not an array.")
|
||||
_locations_loaded = true
|
||||
return
|
||||
|
||||
var loaded_count := 0
|
||||
for item in parsed:
|
||||
if typeof(item) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var location := item as Dictionary
|
||||
var coord_variant: Variant = location.get("coord", {})
|
||||
if typeof(coord_variant) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var coord_dict := coord_variant as Dictionary
|
||||
var coord := Vector2i(int(coord_dict.get("x", 0)), int(coord_dict.get("y", 0)))
|
||||
var location_name := String(location.get("name", "")).strip_edges()
|
||||
if location_name.is_empty():
|
||||
location_name = "Location %d,%d" % [coord.x, coord.y]
|
||||
_known_locations[coord] = location_name
|
||||
loaded_count += 1
|
||||
|
||||
print("LocationLevel loaded %d visible locations for character %s." % [loaded_count, _character_id])
|
||||
if loaded_count == 0:
|
||||
push_warning("Visible locations request succeeded but returned 0 locations for character %s." % _character_id)
|
||||
|
||||
_locations_loaded = true
|
||||
_locations_refresh_in_flight = false
|
||||
_rebuild_tiles(_center_coord)
|
||||
if _queued_locations_refresh:
|
||||
_queued_locations_refresh = false
|
||||
_queue_locations_refresh()
|
||||
|
||||
|
||||
func _queue_locations_refresh() -> void:
|
||||
if _locations_refresh_in_flight:
|
||||
_queued_locations_refresh = true
|
||||
return
|
||||
_refresh_visible_locations()
|
||||
|
||||
|
||||
func _refresh_visible_locations() -> void:
|
||||
if _character_id.is_empty():
|
||||
return
|
||||
_refresh_visible_locations_async()
|
||||
|
||||
|
||||
func _refresh_visible_locations_async() -> void:
|
||||
await _load_existing_locations()
|
||||
|
||||
|
||||
func _queue_coord_sync(coord: Vector2i) -> void:
|
||||
if coord == _persisted_coord:
|
||||
return
|
||||
if _coord_sync_in_flight:
|
||||
_queued_coord_sync = coord
|
||||
return
|
||||
_sync_character_coord(coord)
|
||||
|
||||
|
||||
func _sync_character_coord(coord: Vector2i) -> void:
|
||||
if _character_id.is_empty():
|
||||
return
|
||||
_coord_sync_in_flight = true
|
||||
_queued_coord_sync = null
|
||||
_sync_character_coord_async(coord)
|
||||
|
||||
|
||||
func _sync_character_coord_async(coord: Vector2i) -> void:
|
||||
var response := await CharacterService.update_character_coord(_character_id, coord)
|
||||
if response.get("ok", false):
|
||||
_persisted_coord = coord
|
||||
SelectedCharacter.set_coord(coord)
|
||||
else:
|
||||
push_warning("Failed to persist character coord to %s,%s: status=%s error=%s body=%s" % [
|
||||
coord.x,
|
||||
coord.y,
|
||||
response.get("status", "n/a"),
|
||||
response.get("error", ""),
|
||||
response.get("body", "")
|
||||
])
|
||||
|
||||
_coord_sync_in_flight = false
|
||||
if _queued_coord_sync != null and _queued_coord_sync is Vector2i and _queued_coord_sync != _persisted_coord:
|
||||
var queued_coord: Vector2i = _queued_coord_sync
|
||||
_sync_character_coord(queued_coord)
|
||||
|
||||
@@ -1 +1 @@
|
||||
uid://1fico5npv6dy
|
||||
uid://ctbyn1gws2ahj
|
||||
|
||||
@@ -1,23 +1,32 @@
|
||||
[gd_scene load_steps=4 format=3 uid="uid://b7p7k1i4t0m2l"]
|
||||
[gd_scene load_steps=8 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/Levels/location_level.gd" id="1_6y4q1"]
|
||||
[ext_resource type="Script" path="res://scenes/Levels/location_level.gd" id="1_level_script"]
|
||||
[ext_resource type="PackedScene" path="res://scenes/Characters/location_player.tscn" id="2_player_scene"]
|
||||
[ext_resource type="Material" path="res://assets/materials/kenney_prototype_block_dark.tres" id="3_block_mat"]
|
||||
|
||||
[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_yu2x4"]
|
||||
albedo_color = Color(0.2, 0.6, 0.2, 1)
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_tile"]
|
||||
material = ExtResource("3_block_mat")
|
||||
size = Vector3(1, 1, 1)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_t2a5k"]
|
||||
material = SubResource("StandardMaterial3D_yu2x4")
|
||||
[sub_resource type="Environment" id="Environment_location"]
|
||||
background_mode = 1
|
||||
background_color = Color(0.55, 0.72, 0.92, 1)
|
||||
ambient_light_source = 2
|
||||
ambient_light_color = Color(1, 1, 1, 1)
|
||||
ambient_light_energy = 0.8
|
||||
|
||||
[node name="LocationLevel" type="Node3D"]
|
||||
script = ExtResource("1_6y4q1")
|
||||
script = ExtResource("1_level_script")
|
||||
tracked_node_path = NodePath("Player")
|
||||
|
||||
[node name="TerrainBlock" type="MeshInstance3D" parent="."]
|
||||
mesh = SubResource("BoxMesh_t2a5k")
|
||||
mesh = SubResource("BoxMesh_tile")
|
||||
|
||||
[node name="Player" parent="." instance=ExtResource("2_player_scene")]
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 0, 6, 0)
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.92388, 0.382683, 0, -0.382683, 0.92388, 0, 6, 10)
|
||||
current = true
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
|
||||
environment = SubResource("Environment_location")
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
extends Node3D
|
||||
|
||||
@export var player_spawn_position := Vector3(0.0, 0.0, 0.0)
|
||||
@export var day_length := 120.0
|
||||
@export var start_light_angle := -90.0
|
||||
|
||||
@onready var _player: RigidBody3D = get_node_or_null("Player") as RigidBody3D
|
||||
@onready var _sun: DirectionalLight3D = $DirectionalLight3D
|
||||
|
||||
var _time := 0.0
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_move_player_to_spawn()
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
_update_day_night(delta)
|
||||
|
||||
|
||||
func _move_player_to_spawn() -> void:
|
||||
if _player == null:
|
||||
return
|
||||
_player.global_position = player_spawn_position
|
||||
_player.linear_velocity = Vector3.ZERO
|
||||
_player.angular_velocity = Vector3.ZERO
|
||||
|
||||
|
||||
func _update_day_night(delta: float) -> void:
|
||||
if _sun == null or day_length <= 0.0:
|
||||
return
|
||||
_time = fmod(_time + delta, day_length)
|
||||
var t: float = _time / day_length
|
||||
var angle: float = lerp(start_light_angle, start_light_angle + 360.0, t)
|
||||
_sun.rotation_degrees.x = angle
|
||||
var energy_curve: float = -sin((t * TAU) + (start_light_angle * PI / 180.0))
|
||||
_sun.light_energy = clamp((energy_curve * 1.0) + 0.2, 0.0, 1.2)
|
||||
@@ -0,0 +1 @@
|
||||
uid://c2vm651r4nepy
|
||||
@@ -0,0 +1,60 @@
|
||||
[gd_scene load_steps=9 format=3 uid="uid://b7p7k1i4t0m2l"]
|
||||
|
||||
[ext_resource type="Script" path="res://scenes/Levels/transportation_level.gd" id="1_6y4q1"]
|
||||
[ext_resource type="Script" path="res://scenes/player.gd" id="2_player"]
|
||||
[ext_resource type="PackedScene" path="res://assets/models/TestCharAnimated.glb" id="3_model"]
|
||||
[ext_resource type="PackedScene" path="res://scenes/Interaction/prototype_gateway.tscn" id="4_teleporter"]
|
||||
[ext_resource type="Material" path="res://assets/materials/kenney_prototype_ground_green.tres" id="5_ground_mat"]
|
||||
|
||||
[sub_resource type="SphereShape3D" id="SphereShape3D_player"]
|
||||
|
||||
[sub_resource type="BoxShape3D" id="BoxShape3D_ground"]
|
||||
size = Vector3(1080, 2, 1080)
|
||||
|
||||
[sub_resource type="BoxMesh" id="BoxMesh_ground"]
|
||||
material = ExtResource("5_ground_mat")
|
||||
size = Vector3(1080, 2, 1080)
|
||||
|
||||
[node name="TransportationLevel" type="Node3D"]
|
||||
script = ExtResource("1_6y4q1")
|
||||
|
||||
[node name="Ground" type="StaticBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0)
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Ground"]
|
||||
shape = SubResource("BoxShape3D_ground")
|
||||
|
||||
[node name="MeshInstance3D" type="MeshInstance3D" parent="Ground"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00053596497, 0.0075991154, -0.0019865036)
|
||||
mesh = SubResource("BoxMesh_ground")
|
||||
|
||||
[node name="Player" type="RigidBody3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0)
|
||||
script = ExtResource("2_player")
|
||||
camera_path = NodePath("Camera3D")
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="Player"]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
||||
shape = SubResource("SphereShape3D_player")
|
||||
|
||||
[node name="TestCharAnimated" parent="Player" instance=ExtResource("3_model")]
|
||||
transform = Transform3D(-0.9998549, 0, 0.01703362, 0, 1, 0, -0.01703362, 0, -0.9998549, 0, 0, 0)
|
||||
|
||||
[node name="Camera3D" type="Camera3D" parent="Player"]
|
||||
transform = Transform3D(0.9989785, -4.651856e-10, -0.045188628, 0.006969331, 0.9880354, 0.15407, 0.044647958, -0.15422754, 0.9870261, 0.22036135, 1.8988357, 0.64972365)
|
||||
current = true
|
||||
fov = 49.0
|
||||
|
||||
[node name="SpotLight3D" type="SpotLight3D" parent="Player"]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.906308, -0.422618, 0, 0.422618, 0.906308, 0, 1.7, -0.35)
|
||||
visible = false
|
||||
spot_range = 30.0
|
||||
spot_angle = 25.0
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
|
||||
transform = Transform3D(1, 0, 0, 0, 0.819152, 0.573576, 0, -0.573576, 0.819152, 0, 6, 0)
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="ReturnTeleporter" parent="." instance=ExtResource("4_teleporter")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5.5, 0, 0)
|
||||
target_scene_path = "res://scenes/Levels/level.tscn"
|
||||
Reference in New Issue
Block a user