feat: preventing players from leaving the playable area
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
extends Area3D
|
||||
class_name CombatArea
|
||||
|
||||
var time_left: float = 5.0
|
||||
var time_safe: float = 0.0
|
||||
|
||||
var _player_out_of_bounds: Node3D = null
|
||||
var _ui_layer: CanvasLayer = null
|
||||
var _ui_label: Label = null
|
||||
var _ui_overlay: ColorRect = null
|
||||
|
||||
func _ready() -> void:
|
||||
collision_layer = 0
|
||||
collision_mask = 4294967295 # All layers
|
||||
body_exited.connect(_on_body_exited)
|
||||
body_entered.connect(_on_body_entered)
|
||||
set_process(false)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if _player_out_of_bounds:
|
||||
# Player is outside the combat area!
|
||||
time_left -= delta
|
||||
if time_left <= 0.0:
|
||||
time_left = 0.0
|
||||
_kill_player()
|
||||
|
||||
# Update UI
|
||||
if _ui_label and _ui_overlay:
|
||||
_ui_label.text = "WARNING: RETURN TO COMBAT AREA\n%.1f" % time_left
|
||||
_ui_overlay.color = Color(1.0, 0.0, 0.0, 0.8 * (1.0 - (time_left / 5.0)))
|
||||
else:
|
||||
# Player is inside the combat area, but might have a damaged timer
|
||||
if time_left < 5.0:
|
||||
time_safe += delta
|
||||
if time_safe >= 10.0:
|
||||
time_left = 5.0
|
||||
time_safe = 0.0
|
||||
set_process(false) # Fully recovered, sleep
|
||||
|
||||
func _on_body_exited(body: Node3D) -> void:
|
||||
if body.name == "Player":
|
||||
_player_out_of_bounds = body
|
||||
time_safe = 0.0 # Reset recovery timer
|
||||
_create_ui()
|
||||
set_process(true)
|
||||
|
||||
func _on_body_entered(body: Node3D) -> void:
|
||||
if body == _player_out_of_bounds:
|
||||
_player_out_of_bounds = null
|
||||
_remove_ui()
|
||||
# set_process(true) stays on to tick the time_safe recovery
|
||||
|
||||
func _create_ui() -> void:
|
||||
if _ui_layer: return
|
||||
|
||||
_ui_layer = CanvasLayer.new()
|
||||
_ui_layer.layer = 100 # Put it on top of everything
|
||||
|
||||
_ui_overlay = ColorRect.new()
|
||||
_ui_overlay.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
_ui_overlay.color = Color(1.0, 0.0, 0.0, 0.0)
|
||||
_ui_layer.add_child(_ui_overlay)
|
||||
|
||||
_ui_label = Label.new()
|
||||
_ui_label.set_anchors_preset(Control.PRESET_CENTER)
|
||||
_ui_label.grow_horizontal = Control.GROW_DIRECTION_BOTH
|
||||
_ui_label.grow_vertical = Control.GROW_DIRECTION_BOTH
|
||||
_ui_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||||
_ui_label.add_theme_font_size_override("font_size", 48)
|
||||
_ui_label.add_theme_color_override("font_color", Color(1, 0.2, 0.2))
|
||||
_ui_label.add_theme_color_override("font_outline_color", Color(0, 0, 0))
|
||||
_ui_label.add_theme_constant_override("outline_size", 8)
|
||||
_ui_label.text = "WARNING: RETURN TO COMBAT AREA\n%.1f" % time_left
|
||||
|
||||
_ui_layer.add_child(_ui_label)
|
||||
|
||||
get_tree().current_scene.add_child(_ui_layer)
|
||||
|
||||
func _remove_ui() -> void:
|
||||
if _ui_layer:
|
||||
_ui_layer.queue_free()
|
||||
_ui_layer = null
|
||||
_ui_label = null
|
||||
_ui_overlay = null
|
||||
|
||||
func _kill_player() -> void:
|
||||
if _player_out_of_bounds:
|
||||
# PlayerMovementController's take_damage requires (amount, source)
|
||||
if _player_out_of_bounds.has_method("take_damage"):
|
||||
_player_out_of_bounds.take_damage(9999, Vector3.ZERO)
|
||||
elif "health" in _player_out_of_bounds:
|
||||
_player_out_of_bounds.health = 0
|
||||
if "is_dead" in _player_out_of_bounds:
|
||||
_player_out_of_bounds.is_dead = true
|
||||
|
||||
_player_out_of_bounds = null
|
||||
_remove_ui()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dlqngrm516ddt
|
||||
Reference in New Issue
Block a user