fix(gameplay): escape pause menu + block placement collision + perf optim render_distance/throttling
This commit is contained in:
@@ -83,7 +83,7 @@ toggle_inventory={
|
||||
|
||||
escape={
|
||||
"deadzone": 0.5,
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":16777217,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194305,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
6
scenes/PauseMenu.tscn
Normal file
6
scenes/PauseMenu.tscn
Normal file
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://pause_menu"]
|
||||
|
||||
[ext_resource type="Script" path="res://scripts/PauseMenu.gd" id="1_pause"]
|
||||
|
||||
[node name="PauseMenu" type="Control"]
|
||||
script = ExtResource("1_pause")
|
||||
@@ -7,6 +7,9 @@ extends Node3D
|
||||
|
||||
var inventory: Inventory = Inventory.new()
|
||||
var _inventory_ui: CanvasLayer = null
|
||||
var _pause_menu: Control = null
|
||||
|
||||
var _last_chunk_update_pos: Vector3 = Vector3(99999, 99999, 99999)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -29,6 +32,12 @@ func _ready() -> void:
|
||||
else:
|
||||
push_error("Main: could not load InventoryUI.tscn")
|
||||
|
||||
# Load and attach PauseMenu
|
||||
var pause_scene: PackedScene = preload("res://scenes/PauseMenu.tscn")
|
||||
_pause_menu = pause_scene.instantiate() as Control
|
||||
add_child(_pause_menu)
|
||||
_pause_menu.hide()
|
||||
|
||||
AudioManager.play_ambient_loop("underwater_ambient")
|
||||
AudioManager.play_music("underwater_theme")
|
||||
AudioManager.play_whale_call_random()
|
||||
@@ -51,10 +60,30 @@ func _ready() -> void:
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
# Throttle chunk updates: only when dolphin moved > 4m
|
||||
if dolphin.global_position.distance_to(_last_chunk_update_pos) > 4.0:
|
||||
world.update_player_position(dolphin.global_position)
|
||||
_last_chunk_update_pos = dolphin.global_position
|
||||
plankton_follower.global_position = dolphin.global_position
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if not event.is_action_pressed("escape"):
|
||||
return
|
||||
# Priority: close inventory first if open
|
||||
if _inventory_ui != null and _inventory_ui.get("_is_open"):
|
||||
_inventory_ui.call("_toggle_inventory")
|
||||
get_viewport().set_input_as_handled()
|
||||
return
|
||||
# Toggle pause menu
|
||||
if is_instance_valid(_pause_menu):
|
||||
if _pause_menu.visible:
|
||||
_pause_menu.hide_pause()
|
||||
else:
|
||||
_pause_menu.show_pause()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func _on_block_break(hit_position: Vector3, _normal: Vector3) -> void:
|
||||
var broken_id: int = world.break_block(hit_position)
|
||||
if broken_id > 0:
|
||||
@@ -68,7 +97,17 @@ func _on_block_place(hit_position: Vector3, normal: Vector3) -> void:
|
||||
return
|
||||
if not ItemDatabase.is_placeable(selected["item_id"]):
|
||||
return
|
||||
|
||||
var place_pos := hit_position + normal * 0.5
|
||||
var block_coord := Vector3(floor(place_pos.x), floor(place_pos.y), floor(place_pos.z))
|
||||
var block_center := block_coord + Vector3(0.5, 0.5, 0.5)
|
||||
|
||||
# Refuse if bloc overlaps player AABB (CapsuleShape3D r=0.4 h=2.0)
|
||||
var dolphin_pos: Vector3 = dolphin.global_position
|
||||
var dist := block_center - dolphin_pos
|
||||
if abs(dist.x) < 1.0 and abs(dist.y) < 1.8 and abs(dist.z) < 1.0:
|
||||
return # too close to player, silent refuse
|
||||
|
||||
if world.place_block(place_pos, selected["item_id"]):
|
||||
inventory.remove_item_from_slot(inventory.selected_hotbar, 1)
|
||||
|
||||
|
||||
67
scripts/PauseMenu.gd
Normal file
67
scripts/PauseMenu.gd
Normal file
@@ -0,0 +1,67 @@
|
||||
extends Control
|
||||
|
||||
func _ready() -> void:
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
|
||||
# Semi-transparent background
|
||||
var bg := ColorRect.new()
|
||||
bg.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
bg.color = Color(0, 0, 0, 0.7)
|
||||
add_child(bg)
|
||||
|
||||
# Center VBox
|
||||
var vbox := VBoxContainer.new()
|
||||
vbox.set_anchors_preset(Control.PRESET_CENTER)
|
||||
vbox.add_theme_constant_override("separation", 16)
|
||||
vbox.set_offset(SIDE_LEFT, -120)
|
||||
vbox.set_offset(SIDE_RIGHT, 120)
|
||||
vbox.set_offset(SIDE_TOP, -120)
|
||||
vbox.set_offset(SIDE_BOTTOM, 120)
|
||||
add_child(vbox)
|
||||
|
||||
var title := Label.new()
|
||||
title.text = "PAUSE"
|
||||
title.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
title.add_theme_font_size_override("font_size", 48)
|
||||
vbox.add_child(title)
|
||||
|
||||
var btn_resume := Button.new()
|
||||
btn_resume.text = "Reprendre"
|
||||
btn_resume.pressed.connect(_on_resume)
|
||||
vbox.add_child(btn_resume)
|
||||
|
||||
var btn_menu := Button.new()
|
||||
btn_menu.text = "Menu principal"
|
||||
btn_menu.pressed.connect(_on_main_menu)
|
||||
vbox.add_child(btn_menu)
|
||||
|
||||
var btn_quit := Button.new()
|
||||
btn_quit.text = "Quitter"
|
||||
btn_quit.pressed.connect(_on_quit)
|
||||
vbox.add_child(btn_quit)
|
||||
|
||||
|
||||
func show_pause() -> void:
|
||||
show()
|
||||
get_tree().paused = true
|
||||
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
|
||||
|
||||
|
||||
func hide_pause() -> void:
|
||||
hide()
|
||||
get_tree().paused = false
|
||||
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
|
||||
|
||||
|
||||
func _on_resume() -> void:
|
||||
hide_pause()
|
||||
|
||||
|
||||
func _on_main_menu() -> void:
|
||||
get_tree().paused = false
|
||||
get_tree().change_scene_to_file("res://scenes/MainMenu.tscn")
|
||||
|
||||
|
||||
func _on_quit() -> void:
|
||||
get_tree().quit()
|
||||
@@ -77,13 +77,6 @@ func _setup_input_actions() -> void:
|
||||
ev.button_index = mouse_actions[action_name]
|
||||
InputMap.action_add_event(action_name, ev)
|
||||
|
||||
if not InputMap.has_action("escape"):
|
||||
InputMap.add_action("escape")
|
||||
var ev := InputEventKey.new()
|
||||
ev.keycode = KEY_ESCAPE
|
||||
InputMap.action_add_event("escape", ev)
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||
var motion := event as InputEventMouseMotion
|
||||
@@ -107,11 +100,6 @@ func _input(event: InputEvent) -> void:
|
||||
_do_raycast_place()
|
||||
if event.is_action_pressed("echolocate"):
|
||||
_trigger_echolocation()
|
||||
if event.is_action_pressed("escape"):
|
||||
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
||||
else:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
@@ -252,9 +240,9 @@ func _raycast(reach: float) -> Dictionary:
|
||||
|
||||
func take_damage(amount: float) -> void:
|
||||
health = max(0.0, health - amount)
|
||||
emit_signal("stats_changed", oxygen, health, hunger)
|
||||
stats_changed.emit(oxygen, health, hunger)
|
||||
if health <= 0.0:
|
||||
emit_signal("player_died")
|
||||
player_died.emit()
|
||||
|
||||
|
||||
func _trigger_echolocation() -> void:
|
||||
|
||||
@@ -266,6 +266,9 @@ func _input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("toggle_inventory"):
|
||||
_toggle_inventory()
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("escape") and _is_open:
|
||||
_toggle_inventory()
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
func _toggle_inventory() -> void:
|
||||
|
||||
@@ -8,6 +8,7 @@ var _fish_meshes: Array[MeshInstance3D] = []
|
||||
var _fish_velocities: Array[Vector3] = []
|
||||
var _time: float = 0.0
|
||||
var _player: CharacterBody3D = null
|
||||
var _boid_update_timer: float = 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
_find_player()
|
||||
@@ -62,6 +63,17 @@ func _process(delta: float) -> void:
|
||||
if _player == null:
|
||||
_find_player()
|
||||
|
||||
# Throttle boid calculations to 10 Hz
|
||||
_boid_update_timer += delta
|
||||
if _boid_update_timer >= 0.1:
|
||||
_update_boids(_boid_update_timer)
|
||||
_boid_update_timer = 0.0
|
||||
|
||||
# Apply velocities every frame for smooth movement
|
||||
_apply_velocities(delta)
|
||||
|
||||
|
||||
func _update_boids(dt: float) -> void:
|
||||
for i: int in range(_fish_meshes.size()):
|
||||
var fish: MeshInstance3D = _fish_meshes[i]
|
||||
var vel: Vector3 = _fish_velocities[i]
|
||||
@@ -91,12 +103,12 @@ func _process(delta: float) -> void:
|
||||
avg_vel /= float(neighbor_count)
|
||||
var cohesion_force: Vector3 = (avg_pos - fish.position).normalized() * 0.5
|
||||
var alignment_force: Vector3 = avg_vel.normalized() * 0.3
|
||||
vel += (cohesion_force + alignment_force) * delta * 2.0
|
||||
vel += (cohesion_force + alignment_force) * dt * 2.0
|
||||
|
||||
# --- Global cohesion: return to school center ---
|
||||
var center_offset: Vector3 = fish.position # positions are local to school node
|
||||
var center_offset: Vector3 = fish.position
|
||||
if center_offset.length() > school_radius:
|
||||
vel += -center_offset.normalized() * 1.5 * delta * 4.0
|
||||
vel += -center_offset.normalized() * 1.5 * dt * 4.0
|
||||
|
||||
# --- Player avoidance ---
|
||||
if is_instance_valid(_player):
|
||||
@@ -104,7 +116,7 @@ func _process(delta: float) -> void:
|
||||
var dist_to_player: float = world_fish_pos.distance_to(_player.global_position)
|
||||
if dist_to_player < 3.0:
|
||||
var flee: Vector3 = (world_fish_pos - _player.global_position).normalized()
|
||||
vel += flee * 4.0 * delta * (3.0 - dist_to_player)
|
||||
vel += flee * 4.0 * dt * (3.0 - dist_to_player)
|
||||
|
||||
# Clamp speed
|
||||
if vel.length() > swim_speed * 1.5:
|
||||
@@ -113,6 +125,12 @@ func _process(delta: float) -> void:
|
||||
vel = vel.normalized() * 0.3
|
||||
|
||||
_fish_velocities[i] = vel
|
||||
|
||||
|
||||
func _apply_velocities(delta: float) -> void:
|
||||
for i: int in range(_fish_meshes.size()):
|
||||
var fish: MeshInstance3D = _fish_meshes[i]
|
||||
var vel: Vector3 = _fish_velocities[i]
|
||||
fish.position += vel * delta
|
||||
|
||||
# Rotate mesh to face velocity direction
|
||||
|
||||
@@ -3,7 +3,7 @@ class_name ChunkManager
|
||||
|
||||
const CHUNK_SIZE: int = 16
|
||||
|
||||
@export var render_distance: int = 4
|
||||
@export var render_distance: int = 2
|
||||
@export var world_seed: int = 12345
|
||||
|
||||
var chunks: Dictionary = {}
|
||||
@@ -36,6 +36,26 @@ func update_player_position(pos: Vector3) -> void:
|
||||
if not chunks.has(coord):
|
||||
_load_chunk(coord)
|
||||
|
||||
func _regen_border_neighbors(chunk_coord: Vector3i, local: Vector3i) -> void:
|
||||
# Regen adjacent chunk only if block is on the border face
|
||||
var offsets: Array[Vector3i] = []
|
||||
if local.x == 0:
|
||||
offsets.append(Vector3i(-1, 0, 0))
|
||||
elif local.x == CHUNK_SIZE - 1:
|
||||
offsets.append(Vector3i(1, 0, 0))
|
||||
if local.y == 0:
|
||||
offsets.append(Vector3i(0, -1, 0))
|
||||
elif local.y == CHUNK_SIZE - 1:
|
||||
offsets.append(Vector3i(0, 1, 0))
|
||||
if local.z == 0:
|
||||
offsets.append(Vector3i(0, 0, -1))
|
||||
elif local.z == CHUNK_SIZE - 1:
|
||||
offsets.append(Vector3i(0, 0, 1))
|
||||
for offset: Vector3i in offsets:
|
||||
var neighbor: Vector3i = chunk_coord + offset
|
||||
if chunks.has(neighbor):
|
||||
chunks[neighbor].generate_mesh()
|
||||
|
||||
func break_block(world_pos: Vector3) -> int:
|
||||
var chunk_coord: Vector3i = world_to_chunk_coord(world_pos)
|
||||
if not chunks.has(chunk_coord):
|
||||
@@ -47,6 +67,7 @@ func break_block(world_pos: Vector3) -> int:
|
||||
return 0
|
||||
chunk.set_block(local.x, local.y, local.z, BlockDatabase.BlockType.AIR)
|
||||
chunk.generate_mesh()
|
||||
_regen_border_neighbors(chunk_coord, local)
|
||||
return old_id
|
||||
|
||||
func place_block(world_pos: Vector3, block_id: int) -> bool:
|
||||
@@ -60,6 +81,7 @@ func place_block(world_pos: Vector3, block_id: int) -> bool:
|
||||
return false
|
||||
chunk.set_block(local.x, local.y, local.z, block_id)
|
||||
chunk.generate_mesh()
|
||||
_regen_border_neighbors(chunk_coord, local)
|
||||
return true
|
||||
|
||||
func get_block(world_pos: Vector3) -> int:
|
||||
|
||||
Reference in New Issue
Block a user