Add minimal Bluegill fishing loop
This commit is contained in:
parent
dd2563c0d8
commit
bba93eb3e5
16 changed files with 461 additions and 3 deletions
8
fish/bluegill.tres
Normal file
8
fish/bluegill.tres
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
[gd_resource type="Resource" load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://fish/fish_data.gd" id="1_fish_data"]
|
||||||
|
|
||||||
|
[resource]
|
||||||
|
script = ExtResource("1_fish_data")
|
||||||
|
id = &"bluegill"
|
||||||
|
display_name = "Bluegill"
|
||||||
6
fish/fish_data.gd
Normal file
6
fish/fish_data.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
class_name FishData
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
@export var id: StringName
|
||||||
|
@export var display_name: String
|
||||||
|
@export var icon: Texture2D
|
||||||
1
fish/fish_data.gd.uid
Normal file
1
fish/fish_data.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://h7hg45b7wmst
|
||||||
207
fishing/fishing_spot.gd
Normal file
207
fishing/fishing_spot.gd
Normal file
|
|
@ -0,0 +1,207 @@
|
||||||
|
class_name FishingSpot
|
||||||
|
extends Area3D
|
||||||
|
|
||||||
|
const FishDataType = preload("res://fish/fish_data.gd")
|
||||||
|
const PlayerType = preload("res://player/player.gd")
|
||||||
|
|
||||||
|
signal status_changed(status: String)
|
||||||
|
signal reel_progress_changed(progress: float, visible: bool)
|
||||||
|
|
||||||
|
enum FishingState {
|
||||||
|
READY,
|
||||||
|
WAITING_FOR_BITE,
|
||||||
|
BITE_ACTIVE,
|
||||||
|
REELING,
|
||||||
|
COOLDOWN,
|
||||||
|
}
|
||||||
|
|
||||||
|
@export_category("Timing")
|
||||||
|
@export_range(0.1, 30.0, 0.1) var wait_time: float = 2.0
|
||||||
|
@export_range(0.1, 10.0, 0.1) var bite_window_duration: float = 1.5
|
||||||
|
@export_range(0.1, 10.0, 0.1) var cooldown_duration: float = 1.0
|
||||||
|
@export_range(0.01, 5.0, 0.01) var reel_gain_rate: float = 0.67
|
||||||
|
@export_range(0.01, 5.0, 0.01) var reel_decay_rate: float = 0.2
|
||||||
|
@export_range(0.0, 0.95, 0.05) var hooked_starting_progress: float = 0.25
|
||||||
|
|
||||||
|
@export_category("Catch")
|
||||||
|
@export var catchable_fish: FishDataType
|
||||||
|
|
||||||
|
var state: FishingState = FishingState.READY
|
||||||
|
var _nearby_player: PlayerType
|
||||||
|
var _active_player: PlayerType
|
||||||
|
var _state_time_remaining: float = 0.0
|
||||||
|
var _reel_progress: float = 0.0
|
||||||
|
var _reel_input_held: bool = false
|
||||||
|
var _cooldown_status: String = ""
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
body_entered.connect(_on_body_entered)
|
||||||
|
body_exited.connect(_on_body_exited)
|
||||||
|
|
||||||
|
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
match state:
|
||||||
|
FishingState.WAITING_FOR_BITE:
|
||||||
|
_state_time_remaining -= delta
|
||||||
|
if _state_time_remaining <= 0.0:
|
||||||
|
_activate_bite()
|
||||||
|
FishingState.BITE_ACTIVE:
|
||||||
|
_state_time_remaining -= delta
|
||||||
|
if _state_time_remaining <= 0.0:
|
||||||
|
_miss_bite()
|
||||||
|
FishingState.REELING:
|
||||||
|
if _reel_input_held and not Input.is_action_pressed("fish_primary"):
|
||||||
|
_reel_input_held = false
|
||||||
|
_update_reel_progress(delta)
|
||||||
|
FishingState.COOLDOWN:
|
||||||
|
_state_time_remaining -= delta
|
||||||
|
if _state_time_remaining <= 0.0:
|
||||||
|
_return_to_ready()
|
||||||
|
|
||||||
|
|
||||||
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if _nearby_player == null or not _nearby_player.is_local_control_enabled():
|
||||||
|
return
|
||||||
|
if not event.is_action("fish_primary"):
|
||||||
|
return
|
||||||
|
|
||||||
|
if event.is_pressed():
|
||||||
|
match state:
|
||||||
|
FishingState.READY:
|
||||||
|
_begin_fishing(_nearby_player)
|
||||||
|
FishingState.BITE_ACTIVE:
|
||||||
|
_confirm_hook()
|
||||||
|
FishingState.REELING:
|
||||||
|
_reel_input_held = true
|
||||||
|
_:
|
||||||
|
return
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
elif state == FishingState.REELING:
|
||||||
|
_reel_input_held = false
|
||||||
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
|
|
||||||
|
func _begin_fishing(player: PlayerType) -> void:
|
||||||
|
if state != FishingState.READY or _active_player != null:
|
||||||
|
return
|
||||||
|
|
||||||
|
_active_player = player
|
||||||
|
_active_player.set_movement_enabled(false)
|
||||||
|
state = FishingState.WAITING_FOR_BITE
|
||||||
|
_state_time_remaining = wait_time
|
||||||
|
status_changed.emit("Waiting for a bite...")
|
||||||
|
|
||||||
|
|
||||||
|
func _activate_bite() -> void:
|
||||||
|
if state != FishingState.WAITING_FOR_BITE:
|
||||||
|
return
|
||||||
|
|
||||||
|
state = FishingState.BITE_ACTIVE
|
||||||
|
_state_time_remaining = bite_window_duration
|
||||||
|
status_changed.emit("Bite! Left click to hook")
|
||||||
|
|
||||||
|
|
||||||
|
func _confirm_hook() -> void:
|
||||||
|
if state != FishingState.BITE_ACTIVE or _active_player == null:
|
||||||
|
return
|
||||||
|
|
||||||
|
state = FishingState.REELING
|
||||||
|
_state_time_remaining = 0.0
|
||||||
|
_reel_progress = clampf(hooked_starting_progress, 0.0, 0.95)
|
||||||
|
_reel_input_held = true
|
||||||
|
status_changed.emit("Hold left click to reel")
|
||||||
|
reel_progress_changed.emit(_reel_progress, true)
|
||||||
|
|
||||||
|
|
||||||
|
func _update_reel_progress(delta: float) -> void:
|
||||||
|
if state != FishingState.REELING:
|
||||||
|
return
|
||||||
|
|
||||||
|
if _reel_input_held:
|
||||||
|
_reel_progress = minf(_reel_progress + reel_gain_rate * delta, 1.0)
|
||||||
|
else:
|
||||||
|
_reel_progress = maxf(_reel_progress - reel_decay_rate * delta, 0.0)
|
||||||
|
reel_progress_changed.emit(_reel_progress, true)
|
||||||
|
if is_equal_approx(_reel_progress, 1.0):
|
||||||
|
_resolve_catch()
|
||||||
|
elif is_zero_approx(_reel_progress):
|
||||||
|
_resolve_escape()
|
||||||
|
|
||||||
|
|
||||||
|
func _resolve_catch() -> void:
|
||||||
|
if state != FishingState.REELING or _active_player == null or catchable_fish == null:
|
||||||
|
_cancel_attempt()
|
||||||
|
return
|
||||||
|
|
||||||
|
_active_player.inventory.add_fish(catchable_fish)
|
||||||
|
_cleanup_attempt("Caught %s!" % catchable_fish.display_name)
|
||||||
|
|
||||||
|
|
||||||
|
func _resolve_escape() -> void:
|
||||||
|
if state != FishingState.REELING:
|
||||||
|
return
|
||||||
|
|
||||||
|
var fish_name: String = "The fish"
|
||||||
|
if catchable_fish != null and not catchable_fish.display_name.is_empty():
|
||||||
|
fish_name = "The %s" % catchable_fish.display_name
|
||||||
|
_cleanup_attempt("%s got away!" % fish_name)
|
||||||
|
|
||||||
|
|
||||||
|
func _miss_bite() -> void:
|
||||||
|
if state != FishingState.BITE_ACTIVE:
|
||||||
|
return
|
||||||
|
_cleanup_attempt("The fish got away.")
|
||||||
|
|
||||||
|
|
||||||
|
func _cleanup_attempt(cooldown_message: String = "") -> void:
|
||||||
|
if _active_player != null:
|
||||||
|
_active_player.set_movement_enabled(true)
|
||||||
|
_active_player = null
|
||||||
|
_reel_input_held = false
|
||||||
|
_reel_progress = 0.0
|
||||||
|
reel_progress_changed.emit(0.0, false)
|
||||||
|
|
||||||
|
if cooldown_message.is_empty():
|
||||||
|
state = FishingState.READY
|
||||||
|
_state_time_remaining = 0.0
|
||||||
|
_cooldown_status = ""
|
||||||
|
if _nearby_player != null:
|
||||||
|
status_changed.emit("Left click to cast")
|
||||||
|
else:
|
||||||
|
status_changed.emit("")
|
||||||
|
else:
|
||||||
|
state = FishingState.COOLDOWN
|
||||||
|
_state_time_remaining = cooldown_duration
|
||||||
|
_cooldown_status = cooldown_message
|
||||||
|
status_changed.emit(_cooldown_status)
|
||||||
|
|
||||||
|
|
||||||
|
func _return_to_ready() -> void:
|
||||||
|
_cleanup_attempt()
|
||||||
|
|
||||||
|
|
||||||
|
func _cancel_attempt() -> void:
|
||||||
|
_cleanup_attempt()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_entered(body: Node3D) -> void:
|
||||||
|
if body is not PlayerType or not body.is_local_control_enabled():
|
||||||
|
return
|
||||||
|
if _nearby_player != null:
|
||||||
|
return
|
||||||
|
|
||||||
|
_nearby_player = body
|
||||||
|
if state == FishingState.READY:
|
||||||
|
status_changed.emit("Left click to cast")
|
||||||
|
|
||||||
|
|
||||||
|
func _on_body_exited(body: Node3D) -> void:
|
||||||
|
if body != _nearby_player:
|
||||||
|
return
|
||||||
|
|
||||||
|
_nearby_player = null
|
||||||
|
if body == _active_player:
|
||||||
|
_cancel_attempt()
|
||||||
|
else:
|
||||||
|
status_changed.emit("")
|
||||||
1
fishing/fishing_spot.gd.uid
Normal file
1
fishing/fishing_spot.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c3s0ib16vmyne
|
||||||
44
fishing/fishing_spot.tscn
Normal file
44
fishing/fishing_spot.tscn
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
[gd_scene load_steps=7 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://fishing/fishing_spot.gd" id="1_spot"]
|
||||||
|
[ext_resource type="Resource" path="res://fish/bluegill.tres" id="2_bluegill"]
|
||||||
|
|
||||||
|
[sub_resource type="SphereShape3D" id="RangeShape"]
|
||||||
|
radius = 3.5
|
||||||
|
|
||||||
|
[sub_resource type="CylinderMesh" id="MarkerPostMesh"]
|
||||||
|
top_radius = 0.12
|
||||||
|
bottom_radius = 0.12
|
||||||
|
height = 2.0
|
||||||
|
|
||||||
|
[sub_resource type="TorusMesh" id="RangeMarkerMesh"]
|
||||||
|
inner_radius = 3.35
|
||||||
|
outer_radius = 3.5
|
||||||
|
rings = 32
|
||||||
|
|
||||||
|
[sub_resource type="StandardMaterial3D" id="MarkerMaterial"]
|
||||||
|
albedo_color = Color(0.95, 0.82, 0.18, 1)
|
||||||
|
emission_enabled = true
|
||||||
|
emission = Color(0.3, 0.2, 0.01, 1)
|
||||||
|
emission_energy_multiplier = 0.7
|
||||||
|
|
||||||
|
[node name="FishingSpot" type="Area3D"]
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 2
|
||||||
|
monitoring = true
|
||||||
|
monitorable = false
|
||||||
|
script = ExtResource("1_spot")
|
||||||
|
catchable_fish = ExtResource("2_bluegill")
|
||||||
|
|
||||||
|
[node name="RangeCollision" type="CollisionShape3D" parent="."]
|
||||||
|
shape = SubResource("RangeShape")
|
||||||
|
|
||||||
|
[node name="MarkerPost" type="MeshInstance3D" parent="."]
|
||||||
|
position = Vector3(0, 1, 0)
|
||||||
|
mesh = SubResource("MarkerPostMesh")
|
||||||
|
material_override = SubResource("MarkerMaterial")
|
||||||
|
|
||||||
|
[node name="RangeMarker" type="MeshInstance3D" parent="."]
|
||||||
|
position = Vector3(0, 0.03, 0)
|
||||||
|
mesh = SubResource("RangeMarkerMesh")
|
||||||
|
material_override = SubResource("MarkerMaterial")
|
||||||
21
inventory/fish_inventory.gd
Normal file
21
inventory/fish_inventory.gd
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
class_name FishInventory
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
const FishDataType = preload("res://fish/fish_data.gd")
|
||||||
|
|
||||||
|
signal contents_changed(fish_id: StringName, count: int)
|
||||||
|
|
||||||
|
var _fish_counts: Dictionary[StringName, int] = {}
|
||||||
|
|
||||||
|
|
||||||
|
func add_fish(fish: FishDataType, amount: int = 1) -> void:
|
||||||
|
if fish == null or fish.id.is_empty() or amount <= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
var new_count: int = get_count(fish.id) + amount
|
||||||
|
_fish_counts[fish.id] = new_count
|
||||||
|
contents_changed.emit(fish.id, new_count)
|
||||||
|
|
||||||
|
|
||||||
|
func get_count(fish_id: StringName) -> int:
|
||||||
|
return _fish_counts.get(fish_id, 0)
|
||||||
1
inventory/fish_inventory.gd.uid
Normal file
1
inventory/fish_inventory.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://t4q3l16td1yw
|
||||||
13
main/main.gd
Normal file
13
main/main.gd
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
extends Node3D
|
||||||
|
|
||||||
|
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
|
||||||
|
const GameUIType = preload("res://ui/game_ui.gd")
|
||||||
|
const PlayerType = preload("res://player/player.gd")
|
||||||
|
|
||||||
|
@onready var _player: PlayerType = %Player
|
||||||
|
@onready var _fishing_spot: FishingSpotType = %FishingSpot
|
||||||
|
@onready var _game_ui: GameUIType = %GameUI
|
||||||
|
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
_game_ui.setup(_player.inventory, _fishing_spot)
|
||||||
1
main/main.gd.uid
Normal file
1
main/main.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://c7u6jpr3f33t3
|
||||||
|
|
@ -1,13 +1,25 @@
|
||||||
[gd_scene load_steps=3 format=3]
|
[gd_scene load_steps=6 format=3]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" path="res://world/test_world.tscn" id="1_world"]
|
[ext_resource type="PackedScene" path="res://world/test_world.tscn" id="1_world"]
|
||||||
[ext_resource type="PackedScene" path="res://player/player.tscn" id="2_player"]
|
[ext_resource type="PackedScene" path="res://player/player.tscn" id="2_player"]
|
||||||
|
[ext_resource type="Script" path="res://main/main.gd" id="3_main"]
|
||||||
|
[ext_resource type="PackedScene" path="res://fishing/fishing_spot.tscn" id="4_spot"]
|
||||||
|
[ext_resource type="PackedScene" path="res://ui/game_ui.tscn" id="5_ui"]
|
||||||
|
|
||||||
[node name="Main" type="Node3D"]
|
[node name="Main" type="Node3D"]
|
||||||
|
script = ExtResource("3_main")
|
||||||
|
|
||||||
[node name="TestWorld" parent="." instance=ExtResource("1_world")]
|
[node name="TestWorld" parent="." instance=ExtResource("1_world")]
|
||||||
|
|
||||||
[node name="Players" type="Node3D" parent="."]
|
[node name="Players" type="Node3D" parent="."]
|
||||||
|
|
||||||
[node name="Player" parent="Players" instance=ExtResource("2_player")]
|
[node name="Player" parent="Players" instance=ExtResource("2_player")]
|
||||||
|
unique_name_in_owner = true
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 5)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 5)
|
||||||
|
|
||||||
|
[node name="FishingSpot" parent="." instance=ExtResource("4_spot")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
position = Vector3(0, 1.02, -18)
|
||||||
|
|
||||||
|
[node name="GameUI" parent="." instance=ExtResource("5_ui")]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
class_name Player
|
class_name Player
|
||||||
extends CharacterBody3D
|
extends CharacterBody3D
|
||||||
|
|
||||||
|
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||||
|
|
||||||
@export_category("Movement")
|
@export_category("Movement")
|
||||||
@export var walk_speed: float = 5.0
|
@export var walk_speed: float = 5.0
|
||||||
@export var sprint_speed: float = 8.0
|
@export var sprint_speed: float = 8.0
|
||||||
|
|
@ -9,6 +11,9 @@ extends CharacterBody3D
|
||||||
@export var jump_velocity: float = 6.0
|
@export var jump_velocity: float = 6.0
|
||||||
@export var body_rotation_speed: float = 12.0
|
@export var body_rotation_speed: float = 12.0
|
||||||
|
|
||||||
|
@export_category("Control")
|
||||||
|
@export var local_control_enabled: bool = true
|
||||||
|
|
||||||
@export_category("Camera")
|
@export_category("Camera")
|
||||||
@export var mouse_sensitivity: float = 0.005
|
@export var mouse_sensitivity: float = 0.005
|
||||||
@export var controller_camera_speed: float = 2.5
|
@export var controller_camera_speed: float = 2.5
|
||||||
|
|
@ -24,23 +29,37 @@ extends CharacterBody3D
|
||||||
@onready var _camera_yaw: Node3D = %CameraYaw
|
@onready var _camera_yaw: Node3D = %CameraYaw
|
||||||
@onready var _camera_pitch: Node3D = %CameraPitch
|
@onready var _camera_pitch: Node3D = %CameraPitch
|
||||||
@onready var _spring_arm: SpringArm3D = %SpringArm3D
|
@onready var _spring_arm: SpringArm3D = %SpringArm3D
|
||||||
|
@onready var _camera: Camera3D = %Camera3D
|
||||||
|
@onready var inventory: FishInventoryType = %Inventory
|
||||||
|
|
||||||
var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
var _gravity: float = float(ProjectSettings.get_setting("physics/3d/default_gravity"))
|
||||||
var _camera_dragging: bool = false
|
var _camera_dragging: bool = false
|
||||||
|
var _movement_enabled: bool = true
|
||||||
var _target_zoom: float = 5.0
|
var _target_zoom: float = 5.0
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_target_zoom = clampf(_spring_arm.spring_length, minimum_zoom, maximum_zoom)
|
_target_zoom = clampf(_spring_arm.spring_length, minimum_zoom, maximum_zoom)
|
||||||
_spring_arm.spring_length = _target_zoom
|
_spring_arm.spring_length = _target_zoom
|
||||||
|
_camera.current = local_control_enabled
|
||||||
|
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
func _physics_process(delta: float) -> void:
|
||||||
if not is_on_floor():
|
if not is_on_floor():
|
||||||
velocity.y -= _gravity * delta
|
velocity.y -= _gravity * delta
|
||||||
elif Input.is_action_just_pressed("jump"):
|
elif (
|
||||||
|
local_control_enabled
|
||||||
|
and _movement_enabled
|
||||||
|
and Input.is_action_just_pressed("jump")
|
||||||
|
):
|
||||||
velocity.y = jump_velocity
|
velocity.y = jump_velocity
|
||||||
|
|
||||||
|
if not local_control_enabled or not _movement_enabled:
|
||||||
|
velocity.x = 0.0
|
||||||
|
velocity.z = 0.0
|
||||||
|
move_and_slide()
|
||||||
|
return
|
||||||
|
|
||||||
var input_vector: Vector2 = Input.get_vector(
|
var input_vector: Vector2 = Input.get_vector(
|
||||||
"move_left",
|
"move_left",
|
||||||
"move_right",
|
"move_right",
|
||||||
|
|
@ -69,6 +88,9 @@ func _physics_process(delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
if not local_control_enabled:
|
||||||
|
return
|
||||||
|
|
||||||
if _camera_dragging and not Input.is_action_pressed("camera_drag"):
|
if _camera_dragging and not Input.is_action_pressed("camera_drag"):
|
||||||
_camera_dragging = false
|
_camera_dragging = false
|
||||||
|
|
||||||
|
|
@ -88,6 +110,9 @@ func _process(delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
|
if not local_control_enabled:
|
||||||
|
return
|
||||||
|
|
||||||
if event.is_action("camera_drag"):
|
if event.is_action("camera_drag"):
|
||||||
_camera_dragging = event.is_pressed()
|
_camera_dragging = event.is_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
@ -127,3 +152,22 @@ func _rotate_camera(delta_rotation: Vector2) -> void:
|
||||||
|
|
||||||
func _set_target_zoom(value: float) -> void:
|
func _set_target_zoom(value: float) -> void:
|
||||||
_target_zoom = clampf(value, minimum_zoom, maximum_zoom)
|
_target_zoom = clampf(value, minimum_zoom, maximum_zoom)
|
||||||
|
|
||||||
|
|
||||||
|
func set_local_control(enabled: bool) -> void:
|
||||||
|
local_control_enabled = enabled
|
||||||
|
if is_node_ready():
|
||||||
|
_camera.current = enabled
|
||||||
|
if not enabled:
|
||||||
|
_camera_dragging = false
|
||||||
|
|
||||||
|
|
||||||
|
func is_local_control_enabled() -> bool:
|
||||||
|
return local_control_enabled
|
||||||
|
|
||||||
|
|
||||||
|
func set_movement_enabled(enabled: bool) -> void:
|
||||||
|
_movement_enabled = enabled
|
||||||
|
if not enabled:
|
||||||
|
velocity.x = 0.0
|
||||||
|
velocity.z = 0.0
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
[gd_scene load_steps=7 format=3]
|
[gd_scene load_steps=8 format=3]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://player/player.gd" id="1_script"]
|
[ext_resource type="Script" path="res://player/player.gd" id="1_script"]
|
||||||
|
[ext_resource type="Script" path="res://inventory/fish_inventory.gd" id="2_inventory"]
|
||||||
|
|
||||||
[sub_resource type="CapsuleShape3D" id="PlayerShape"]
|
[sub_resource type="CapsuleShape3D" id="PlayerShape"]
|
||||||
radius = 0.45
|
radius = 0.45
|
||||||
|
|
@ -41,6 +42,10 @@ position = Vector3(0, 1.0, -0.55)
|
||||||
mesh = SubResource("FacingMarkerMesh")
|
mesh = SubResource("FacingMarkerMesh")
|
||||||
material_override = SubResource("FacingMarkerMaterial")
|
material_override = SubResource("FacingMarkerMaterial")
|
||||||
|
|
||||||
|
[node name="Inventory" type="Node" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
script = ExtResource("2_inventory")
|
||||||
|
|
||||||
[node name="CameraYaw" type="Node3D" parent="."]
|
[node name="CameraYaw" type="Node3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
position = Vector3(0, 1.35, 0)
|
position = Vector3(0, 1.35, 0)
|
||||||
|
|
@ -56,4 +61,5 @@ margin = 0.15
|
||||||
collision_mask = 1
|
collision_mask = 1
|
||||||
|
|
||||||
[node name="Camera3D" type="Camera3D" parent="CameraYaw/CameraPitch/SpringArm3D"]
|
[node name="Camera3D" type="Camera3D" parent="CameraYaw/CameraPitch/SpringArm3D"]
|
||||||
|
unique_name_in_owner = true
|
||||||
current = true
|
current = true
|
||||||
|
|
|
||||||
35
ui/game_ui.gd
Normal file
35
ui/game_ui.gd
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
class_name GameUI
|
||||||
|
extends CanvasLayer
|
||||||
|
|
||||||
|
const FishInventoryType = preload("res://inventory/fish_inventory.gd")
|
||||||
|
const FishingSpotType = preload("res://fishing/fishing_spot.gd")
|
||||||
|
|
||||||
|
@onready var _status_label: Label = %StatusLabel
|
||||||
|
@onready var _bluegill_count_label: Label = %BluegillCountLabel
|
||||||
|
@onready var _reel_progress: ProgressBar = %ReelProgress
|
||||||
|
|
||||||
|
|
||||||
|
func setup(inventory: FishInventoryType, fishing_spot: FishingSpotType) -> void:
|
||||||
|
inventory.contents_changed.connect(_on_inventory_contents_changed)
|
||||||
|
fishing_spot.status_changed.connect(_on_fishing_status_changed)
|
||||||
|
fishing_spot.reel_progress_changed.connect(_on_reel_progress_changed)
|
||||||
|
_update_bluegill_count(inventory.get_count(&"bluegill"))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_inventory_contents_changed(fish_id: StringName, count: int) -> void:
|
||||||
|
if fish_id == &"bluegill":
|
||||||
|
_update_bluegill_count(count)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_fishing_status_changed(status: String) -> void:
|
||||||
|
_status_label.text = status
|
||||||
|
_status_label.visible = not status.is_empty()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_reel_progress_changed(progress: float, visible: bool) -> void:
|
||||||
|
_reel_progress.value = progress * 100.0
|
||||||
|
_reel_progress.visible = visible
|
||||||
|
|
||||||
|
|
||||||
|
func _update_bluegill_count(count: int) -> void:
|
||||||
|
_bluegill_count_label.text = "Bluegill: %d" % count
|
||||||
1
ui/game_ui.gd.uid
Normal file
1
ui/game_ui.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bhxprtqbieqvc
|
||||||
57
ui/game_ui.tscn
Normal file
57
ui/game_ui.tscn
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
[gd_scene load_steps=2 format=3]
|
||||||
|
|
||||||
|
[ext_resource type="Script" path="res://ui/game_ui.gd" id="1_ui"]
|
||||||
|
|
||||||
|
[node name="GameUI" type="CanvasLayer"]
|
||||||
|
script = ExtResource("1_ui")
|
||||||
|
|
||||||
|
[node name="InventoryPanel" type="PanelContainer" parent="."]
|
||||||
|
offset_left = 16.0
|
||||||
|
offset_top = 16.0
|
||||||
|
offset_right = 176.0
|
||||||
|
offset_bottom = 62.0
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="InventoryPanel"]
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 8
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 8
|
||||||
|
|
||||||
|
[node name="BluegillCountLabel" type="Label" parent="InventoryPanel/MarginContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
text = "Bluegill: 0"
|
||||||
|
|
||||||
|
[node name="FishingPanel" type="PanelContainer" parent="."]
|
||||||
|
anchors_preset = 7
|
||||||
|
anchor_left = 0.5
|
||||||
|
anchor_top = 1.0
|
||||||
|
anchor_right = 0.5
|
||||||
|
anchor_bottom = 1.0
|
||||||
|
offset_left = -160.0
|
||||||
|
offset_top = -100.0
|
||||||
|
offset_right = 160.0
|
||||||
|
offset_bottom = -20.0
|
||||||
|
grow_horizontal = 2
|
||||||
|
grow_vertical = 0
|
||||||
|
mouse_filter = 2
|
||||||
|
|
||||||
|
[node name="MarginContainer" type="MarginContainer" parent="FishingPanel"]
|
||||||
|
theme_override_constants/margin_left = 12
|
||||||
|
theme_override_constants/margin_top = 8
|
||||||
|
theme_override_constants/margin_right = 12
|
||||||
|
theme_override_constants/margin_bottom = 8
|
||||||
|
|
||||||
|
[node name="VBoxContainer" type="VBoxContainer" parent="FishingPanel/MarginContainer"]
|
||||||
|
|
||||||
|
[node name="StatusLabel" type="Label" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
text = "Left click to cast"
|
||||||
|
horizontal_alignment = 1
|
||||||
|
|
||||||
|
[node name="ReelProgress" type="ProgressBar" parent="FishingPanel/MarginContainer/VBoxContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
visible = false
|
||||||
|
custom_minimum_size = Vector2(0, 18)
|
||||||
|
value = 0.0
|
||||||
|
show_percentage = false
|
||||||
Loading…
Add table
Add a link
Reference in a new issue