部署 portal,note,npc,ambush,inspectable(尚未完全实现其功能)

This commit is contained in:
cakipaul 2024-12-27 15:56:45 +08:00
parent 76f43eaa8d
commit f269e57507
32 changed files with 671 additions and 306 deletions

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=2 format=3 uid="uid://d4al2cij8etly"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_j4sse"]
[resource]
script = ExtResource("1_j4sse")
audios = null

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://js1tl82m1ky7"]
[ext_resource type="AudioStream" uid="uid://cqukq4oo43iba" path="res://asset/audio/effect/impact/impactMetal_heavy_000.ogg" id="1_5e1s4"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_gwpkx"]
[ext_resource type="AudioStream" uid="uid://dj8ug26pqfqk6" path="res://asset/audio/effect/impact/impactMetal_heavy_001.ogg" id="2_j5lg3"]
[ext_resource type="AudioStream" uid="uid://778bt8rfi0gl" path="res://asset/audio/effect/impact/impactMetal_heavy_002.ogg" id="3_vu1i8"]
[ext_resource type="AudioStream" uid="uid://jcb24rwagg4o" path="res://asset/audio/effect/impact/impactMetal_heavy_003.ogg" id="4_3kjn2"]
[ext_resource type="AudioStream" uid="uid://cje3xqf7sasnk" path="res://asset/audio/effect/impact/impactMetal_heavy_004.ogg" id="5_rc31t"]
[resource]
script = ExtResource("1_gwpkx")
audios = Array[AudioStream]([ExtResource("1_5e1s4"), ExtResource("2_j5lg3"), ExtResource("3_vu1i8"), ExtResource("4_3kjn2"), ExtResource("5_rc31t")])

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://d4al2cij8etly"]
[ext_resource type="AudioStream" uid="uid://ue5cwfwf1wt8" path="res://asset/audio/effect/impact/impactMetal_light_000.ogg" id="1_s2lji"]
[ext_resource type="AudioStream" uid="uid://c01ptw0axvgdt" path="res://asset/audio/effect/impact/impactMetal_light_001.ogg" id="2_3cweu"]
[ext_resource type="AudioStream" uid="uid://b13oxscxj2h3v" path="res://asset/audio/effect/impact/impactMetal_light_002.ogg" id="3_37sa6"]
[ext_resource type="AudioStream" uid="uid://dhpxxtc62ayjr" path="res://asset/audio/effect/impact/impactMetal_light_003.ogg" id="4_g5717"]
[ext_resource type="AudioStream" uid="uid://ko5mmaahf0xb" path="res://asset/audio/effect/impact/impactMetal_light_004.ogg" id="5_n7t7w"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="6_e13in"]
[resource]
script = ExtResource("6_e13in")
audios = Array[AudioStream]([ExtResource("1_s2lji"), ExtResource("2_3cweu"), ExtResource("3_37sa6"), ExtResource("4_g5717"), ExtResource("5_n7t7w")])

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://ddfblslvntgu"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_g418v"]
[ext_resource type="AudioStream" uid="uid://c811574l1sim6" path="res://asset/audio/effect/impact/impactMetal_medium_000.ogg" id="1_wd60t"]
[ext_resource type="AudioStream" uid="uid://cur5c3t70ni27" path="res://asset/audio/effect/impact/impactMetal_medium_001.ogg" id="2_g2sas"]
[ext_resource type="AudioStream" uid="uid://50rruyuau2qn" path="res://asset/audio/effect/impact/impactMetal_medium_002.ogg" id="3_073c3"]
[ext_resource type="AudioStream" uid="uid://8lhiw67itd6m" path="res://asset/audio/effect/impact/impactMetal_medium_003.ogg" id="4_hehtc"]
[ext_resource type="AudioStream" uid="uid://ce6bc4o0p8ky" path="res://asset/audio/effect/impact/impactMetal_medium_004.ogg" id="5_j2fcx"]
[resource]
script = ExtResource("1_g418v")
audios = Array[AudioStream]([ExtResource("1_wd60t"), ExtResource("2_g2sas"), ExtResource("3_073c3"), ExtResource("4_hehtc"), ExtResource("5_j2fcx")])

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://dyx67l4nd53nc"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_6llnf"]
[ext_resource type="AudioStream" uid="uid://conjpb7ggfw6f" path="res://asset/audio/effect/impact/impactMining_000.ogg" id="1_jjr4n"]
[ext_resource type="AudioStream" uid="uid://b4y06rr6gv8y" path="res://asset/audio/effect/impact/impactMining_001.ogg" id="2_jmhjt"]
[ext_resource type="AudioStream" uid="uid://d3khv1m8gy2uo" path="res://asset/audio/effect/impact/impactMining_002.ogg" id="3_jjf1d"]
[ext_resource type="AudioStream" uid="uid://cfdxef7x3t0hq" path="res://asset/audio/effect/impact/impactMining_003.ogg" id="4_5fikd"]
[ext_resource type="AudioStream" uid="uid://tnatkl3ncvfx" path="res://asset/audio/effect/impact/impactMining_004.ogg" id="5_5ns5a"]
[resource]
script = ExtResource("1_6llnf")
audios = Array[AudioStream]([ExtResource("1_jjr4n"), ExtResource("2_jmhjt"), ExtResource("3_jjf1d"), ExtResource("4_5fikd"), ExtResource("5_5ns5a")])

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://b2e6foy2bgnf4"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_pwu5t"]
[ext_resource type="AudioStream" uid="uid://chwobtysckx42" path="res://asset/audio/effect/impact/impactSoft_heavy_000.ogg" id="1_ytmeo"]
[ext_resource type="AudioStream" uid="uid://cfebvnl31ao8a" path="res://asset/audio/effect/impact/impactSoft_heavy_001.ogg" id="2_k5guy"]
[ext_resource type="AudioStream" uid="uid://b5f6b5xkn45m6" path="res://asset/audio/effect/impact/impactSoft_heavy_002.ogg" id="3_isu8f"]
[ext_resource type="AudioStream" uid="uid://byyno2jmpabx4" path="res://asset/audio/effect/impact/impactSoft_heavy_003.ogg" id="4_f0c6t"]
[ext_resource type="AudioStream" uid="uid://c056qfqjh50ot" path="res://asset/audio/effect/impact/impactSoft_heavy_004.ogg" id="5_wn3xo"]
[resource]
script = ExtResource("1_pwu5t")
audios = Array[AudioStream]([ExtResource("1_ytmeo"), ExtResource("2_k5guy"), ExtResource("3_isu8f"), ExtResource("4_f0c6t"), ExtResource("5_wn3xo")])

View File

@ -0,0 +1,12 @@
[gd_resource type="Resource" script_class="AudioStreamCollection" load_steps=7 format=3 uid="uid://bfx5fndaqomvv"]
[ext_resource type="AudioStream" uid="uid://ddf5vkcue0yxd" path="res://asset/audio/effect/impact/impactSoft_medium_000.ogg" id="1_1dffb"]
[ext_resource type="Script" path="res://config/audio/audio_stream_collection.gd" id="1_b71n3"]
[ext_resource type="AudioStream" uid="uid://coiw0mtaw0g2o" path="res://asset/audio/effect/impact/impactSoft_medium_001.ogg" id="2_fefja"]
[ext_resource type="AudioStream" uid="uid://btx5nss8hq8jh" path="res://asset/audio/effect/impact/impactSoft_medium_002.ogg" id="3_oxjxn"]
[ext_resource type="AudioStream" uid="uid://d4mhqixpy8vsf" path="res://asset/audio/effect/impact/impactSoft_medium_003.ogg" id="4_d2k3p"]
[ext_resource type="AudioStream" uid="uid://c0cuydy3pgfs4" path="res://asset/audio/effect/impact/impactSoft_medium_004.ogg" id="5_ykira"]
[resource]
script = ExtResource("1_b71n3")
audios = Array[AudioStream]([ExtResource("1_1dffb"), ExtResource("2_fefja"), ExtResource("3_oxjxn"), ExtResource("4_d2k3p"), ExtResource("5_ykira")])

View File

@ -26,5 +26,5 @@ const FOOTSTEP_AUDIO = {
## sound
@export_enum("none", "wood", "carpet", "concrete", "grass", "snow")
var footstep_type: String = "grass"
var footstep_type: String = "concrete"
var bgm: String = ""

View File

@ -1,11 +1,5 @@
extends Node
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func play_cg(cg_name: String) -> void:
print("play_cg: ", cg_name)

View File

@ -1,8 +1,39 @@
extends Node
func get_player() -> MainPlayer:
return get_node_or_null("/root/Main/MainPlayer") as MainPlayer
func get_ground_loader() -> GroundLoader:
return get_node_or_null("/root/Main/GroundLoader") as GroundLoader
func pop_notification(msg: String, number := 1) -> void:
var notification_node = get_node_or_null("/root/Main/UILayer/Notification")
if notification_node:
notification_node.show_notification(msg, number)
else:
printerr("Notification node not found")
printerr("Notification node not found")
func pop_dialog(
character: String,
content: String,
character_color := "orange",
content_color := "white",
duration := 2.5
) -> void:
var dialog_node = get_node_or_null("/root/Main/UILayer/Dialog")
if dialog_node:
dialog_node.append_dialog(character, content, character_color, content_color, duration)
else:
printerr("Dialog node not found")
func pop_note(note: String, note_color := "white", duration := 2.5) -> void:
var dialog_node = get_node_or_null("/root/Main/UILayer/Dialog")
if dialog_node:
dialog_node.append_note(note, note_color, duration)
else:
printerr("Dialog node not found")

View File

@ -3,8 +3,8 @@ extends Marker2D
@export var lock_horizontal = true
func tweak_position(velocity, facing_direction):
position.x = facing_direction.x * abs(velocity.x) * 0.2
position.x = facing_direction.x * abs(velocity.x) * 0.4
if lock_horizontal:
global_position.y = 0
else:
position.y = facing_direction.y * abs(velocity.y) * 0.2
position.y = facing_direction.y * abs(velocity.y) * 0.4

74
scene/dialog/dialog.gd Normal file
View File

@ -0,0 +1,74 @@
extends Control
@onready var label = %RichTextLabel as RichTextLabel
var pending_bbcode = []
var tweening := false
func _ready():
label.clear()
modulate = Color(1, 1, 1, 0)
# test notification in editor
if GlobalConfig.DEBUG:
call_deferred("test")
func test():
# append_dialog("吕萍", "Hello, 2! very very long message, very very loooonnnggggggg!")
# append_note("Hello, 3!")
# append_note("Hello, blue!", "blue", 1)
append_dialog("车夫", "你好!", "green")
func append_note(note: String, note_color := "white", duration := 2.5) -> void:
pending_bbcode.append(
["[center][color=" + note_color + "]" + note + "[/color][/center]", duration]
)
_show()
func append_dialog(
character: String,
content: String,
character_color := "orange",
content_color := "white",
duration := 2.5
) -> void:
pending_bbcode.append(
[
(
"[center][color="
+ character_color
+ "][b]"
+ character
+ ":[/b][/color][color="
+ content_color
+ "]"
+ content
+ "[/color][/center]"
),
duration
]
)
_show()
func _show() -> void:
if not tweening and pending_bbcode.size() > 0:
var tuple = pending_bbcode.pop_front()
label.parse_bbcode(tuple[0])
tweening = true
var tween = create_tween()
# 0.5s to show the notification
tween.tween_property(self, "modulate:a", 1, 0.2).set_trans(Tween.TRANS_CUBIC)
# keep the notification
tween.tween_interval(max(tuple[1] - 0.4, 0))
# 0.5s to hide the notification
tween.tween_property(self, "modulate:a", 0, 0.2).set_trans(Tween.TRANS_CUBIC)
# callback
tween.tween_callback(_check_next)
func _check_next():
tweening = false
_show()

View File

@ -1,8 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://dmkt1roqc4he7"]
[ext_resource type="Script" path="res://scene/dialog/dialog_container.gd" id="1_s1ka3"]
[ext_resource type="Script" path="res://scene/dialog/dialog.gd" id="1_s1ka3"]
[node name="DialogContainer" type="MarginContainer"]
[node name="Dialog" type="MarginContainer"]
anchors_preset = 7
anchor_left = 0.5
anchor_top = 1.0

View File

@ -1,31 +0,0 @@
extends Control
@export var character := "吕萍":
set(value):
character = value
_reload()
@export var character_color := "orange":
set(value):
character_color = value
_reload()
@export var content := "你好,我是吕萍。":
set(value):
content = value
_reload()
@export var content_color := "white":
set(value):
content_color = value
_reload()
@onready var label = %RichTextLabel as RichTextLabel
func _ready():
_reload()
func _reload():
label.clear()
label.append_bbcode("[color=" + character_color + "][b]" + character + "[/b]:[/color]")
label.append_bbcode("[color=" + content_color + "]" + content + "[/color]")
func append():
pass

25
scene/entity/ambush.gd Normal file
View File

@ -0,0 +1,25 @@
extends Node2D
@export var one_shot := true
@export var hook_cg = ""
var played := false
@onready var area2d = %Area2D as Area2D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
area2d.body_entered.connect(_entered)
func _entered(_body):
print("ambush body_entered!")
if one_shot and played:
queue_free()
return
# hook_cg
if hook_cg != "":
CgManager.play_cg(hook_cg)
if one_shot:
queue_free()

16
scene/entity/ambush.tscn Normal file
View File

@ -0,0 +1,16 @@
[gd_scene load_steps=3 format=3 uid="uid://bnf3lkcbpx1ar"]
[ext_resource type="Script" path="res://scene/entity/ambush.gd" id="1_rxgbr"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_iwrfx"]
resource_local_to_scene = true
size = Vector2(60, 100)
[node name="Ambush" type="Node2D"]
script = ExtResource("1_rxgbr")
[node name="Area2D" type="Area2D" parent="."]
unique_name_in_owner = true
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
shape = SubResource("RectangleShape2D_iwrfx")

View File

@ -1,28 +1,43 @@
extends Sprite2D
@export var entity_config: EntityConfig:
set(value):
entity_config = value
# @export var entity_config: EntityConfig:
# set(value):
# entity_config = value
@export var entity_name: String = ""
@export var entity_title: String = ""
@export var inspection_texture: Texture2D
@export var inspection_note: String = ""
@onready var sprite2d = %AnimatedSoundSprite2D as AnimatedSoundSprite2D
@onready var sign_mark = %Sign as Sprite2D
@onready var area2d = %InteractArea2D as Area2D
@onready var collision_shape = %CollisionShape2D as CollisionShape2D
@onready var area2d = %Area2D as Area2D
var listening = false
func _ready() -> void:
_relocate_sign()
area2d.body_entered.connect(_reset)
area2d.body_exited.connect(_on_cancel)
area2d.body_entered.connect(sign_mark.activate)
area2d.body_exited.connect(sign_mark.disactivate)
sign_mark.interacted.connect(_on_interacted)
sign_mark.cancel.connect(_on_cancel)
# if GlobalConfig.DEBUG:
# var label = DebugLabel.new()
# add_child(label)
# label.name = "DebugLabel"
func _on_interacted() -> void:
pass
func _on_cancel(_body = null):
pass
func _reset(_body):
pass
# _reload()
# func _reload() -> void:
@ -53,16 +68,3 @@ func _ready() -> void:
# if label:
# label.text = ("[" + entity_config.entity_name + "]" + entity_config.entity_title)
# label.modulate = Color.GREEN
func _relocate_sign():
# 根据 sprite 大小,调整位置
pass
func _on_interacted() -> void:
pass
func _on_cancel():
pass
func _reset():
pass

View File

@ -0,0 +1,47 @@
[gd_scene load_steps=9 format=3 uid="uid://wyj4qdjyn4ql"]
[ext_resource type="Script" path="res://scene/entity/inspectable.gd" id="1_0pc4s"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="2_fcru3"]
[ext_resource type="Texture2D" uid="uid://dvg6wjwn1qxiv" path="res://asset/art/ui/action_mark/探索ui.png" id="3_s7dto"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="3_vbivp"]
[ext_resource type="Resource" uid="uid://d0wynwv8stclg" path="res://config/audio/action/action_book_open.tres" id="4_v1qpa"]
[ext_resource type="SpriteFrames" uid="uid://c3s8u4ifaucpj" path="res://config/animation/entity_sprite_frames.tres" id="7_njjhh"]
[ext_resource type="Script" path="res://manager/deploy/entity/animated_sound_sprite_2d.gd" id="8_wntgt"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_4fuic"]
resource_local_to_scene = true
size = Vector2(35, 70)
[node name="Inspectable" type="Sprite2D"]
script = ExtResource("1_0pc4s")
[node name="PointLight2D" type="PointLight2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -35)
scale = Vector2(0.2, 0.2)
energy = 0.0
texture = ExtResource("3_vbivp")
texture_scale = 0.5
[node name="Sign" type="Sprite2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -52)
scale = Vector2(0.2, 0.2)
texture = ExtResource("3_s7dto")
script = ExtResource("2_fcru3")
audio_collection = ExtResource("4_v1qpa")
[node name="AnimatedSoundSprite2D" type="AnimatedSprite2D" parent="."]
unique_name_in_owner = true
visible = false
sprite_frames = ExtResource("7_njjhh")
animation = &"c00_吕萍_记笔记_right"
script = ExtResource("8_wntgt")
[node name="Area2D" type="Area2D" parent="."]
unique_name_in_owner = true
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
unique_name_in_owner = true
shape = SubResource("RectangleShape2D_4fuic")

View File

@ -1,80 +0,0 @@
[gd_scene load_steps=10 format=3 uid="uid://do5j7vqrviv48"]
[ext_resource type="Script" path="res://scene/entity/normal.gd" id="1_thex5"]
[ext_resource type="SpriteFrames" uid="uid://c3s8u4ifaucpj" path="res://config/animation/entity_sprite_frames.tres" id="3_3rf47"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="3_4nd6g"]
[ext_resource type="Texture2D" uid="uid://dvg6wjwn1qxiv" path="res://asset/art/ui/action_mark/探索ui.png" id="3_thqpp"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="4_3ohmd"]
[ext_resource type="Script" path="res://manager/deploy/entity/animated_sound_sprite_2d.gd" id="4_bsxot"]
[sub_resource type="GDScript" id="GDScript_ngryc"]
script/source = "class_name EntityConfig extends Resource
# class EntityStateConfig:
# extends Resource
# var animation: String = \"\"
# var scale: Vector2 = Vector2.ONE
# var offset: Vector2 = Vector2.ZERO
# var expected_duration: float = 1.0 # for placeholder demo only
# var loop: bool = false # set with animation
# var sound: String = \"\" # bind to animation
@export var entity_name: String = \"\"
@export var entity_title: String = \"\"
# @export var entity_notes := [] as Array[String]
# @export var hud_texture: Texture2D
# @export var pickable := false
@export var inspection_texture: Texture2D
@export var inspection_note: String = \"\"
@export var inspection_gameplay: PackedScene
# @export var offset := Vector2.ZERO
# @export var scale := Vector2.ONE
# @export var physical_vibe_effect: PackedScene
# @export var hud_thumbnail := \"\" # searched by entity_name
# @export var entity_state_inspection: EntityStateConfig
@export var placeholder_size := Vector2(32, 64)
"
[sub_resource type="Resource" id="Resource_w82oj"]
script = SubResource("GDScript_ngryc")
entity_name = "placeholder"
entity_title = ""
inspection_note = ""
placeholder_size = Vector2(32, 64)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_4fuic"]
resource_local_to_scene = true
size = Vector2(33, 43)
[node name="Normal" type="Sprite2D"]
script = ExtResource("1_thex5")
entity_config = SubResource("Resource_w82oj")
[node name="Sign" type="Sprite2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -35)
scale = Vector2(0.2, 0.2)
texture = ExtResource("3_thqpp")
script = ExtResource("3_4nd6g")
[node name="PointLight2D" type="PointLight2D" parent="Sign"]
unique_name_in_owner = true
position = Vector2(0, -2.54313e-05)
energy = 0.1
texture = ExtResource("4_3ohmd")
texture_scale = 0.5
[node name="AnimatedSoundSprite2D" type="AnimatedSprite2D" parent="."]
unique_name_in_owner = true
visible = false
sprite_frames = ExtResource("3_3rf47")
script = ExtResource("4_bsxot")
[node name="InteractArea2D" type="Area2D" parent="."]
unique_name_in_owner = true
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="InteractArea2D"]
unique_name_in_owner = true
shape = SubResource("RectangleShape2D_4fuic")

View File

@ -5,23 +5,38 @@ extends Marker2D
@onready var sign_mark = %Sign as Sprite2D
@onready var area2d = %Area2D as Area2D
var listening = false
var played_time = 0
var mutex = Mutex.new()
func _ready() -> void:
area2d.body_entered.connect(_reset)
area2d.body_exited.connect(_on_cancel)
area2d.body_entered.connect(sign_mark.activate)
area2d.body_exited.connect(sign_mark.disactivate)
sign_mark.interacted.connect(_on_interacted)
sign_mark.cancel.connect(_on_cancel)
func _on_interacted() -> void:
print("note interacted")
if notes.is_empty():
return
var note_time = notes.size() * 2.5
# 0.5s 内锁定播放
mutex.lock()
if Time.get_ticks_msec() - played_time < note_time * 1000 + 500:
return
# show note
played_time = Time.get_ticks_msec()
mutex.unlock()
for note in notes:
SceneManager.pop_note(note, "white", 2.5)
var player = SceneManager.get_player()
player.check_note(note_time)
func _on_cancel():
func _on_cancel(_body = null):
pass
func _reset():
func _reset(_body):
pass

View File

@ -2,13 +2,13 @@
[ext_resource type="Script" path="res://scene/entity/note.gd" id="1_3igk8"]
[ext_resource type="Texture2D" uid="uid://dvg6wjwn1qxiv" path="res://asset/art/ui/action_mark/探索ui.png" id="1_eew1k"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="3_2x3g1"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="2_36okt"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="3_xb81s"]
[ext_resource type="Resource" uid="uid://d0wynwv8stclg" path="res://config/audio/action/action_book_open.tres" id="4_14cx5"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_k6och"]
resource_local_to_scene = true
size = Vector2(60, 150)
size = Vector2(45, 100)
[node name="Note" type="Marker2D"]
script = ExtResource("1_3igk8")
@ -16,16 +16,17 @@ notes = Array[String](["(note)"])
[node name="Sign" type="Sprite2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -35)
position = Vector2(0, -63)
scale = Vector2(0.2, 0.2)
texture = ExtResource("1_eew1k")
script = ExtResource("3_2x3g1")
script = ExtResource("2_36okt")
audio_collection = ExtResource("4_14cx5")
[node name="PointLight2D" type="PointLight2D" parent="Sign"]
[node name="PointLight2D" type="PointLight2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -2.54313e-05)
energy = 0.1
position = Vector2(0, -35)
scale = Vector2(0.2, 0.2)
energy = 0.0
texture = ExtResource("3_xb81s")
texture_scale = 0.5

View File

@ -1,27 +1,30 @@
extends AnimatedSprite2D
@onready var speaking_sign = %SpeakingSignAnimation as AnimatedSprite2D
@export var dialogs := []
@onready var speaking_animation = %SpeakingAnimationPlayer
@onready var speaking_sign = %SpeakingSign2D as Node2D
@onready var sign_mark = %Sign as Sprite2D
@onready var area2d = %Area2D as Area2D
var dialog_played := false
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
area2d.body_entered.connect(_reset)
area2d.body_exited.connect(_on_cancel)
area2d.body_entered.connect(sign_mark.activate)
area2d.body_exited.connect(sign_mark.disactivate)
sign_mark.interacted.connect(_on_interacted)
sign_mark.cancel.connect(_on_cancel)
func _on_interacted() -> void:
print("npc interacted")
pass
func _on_cancel():
pass
func _on_cancel(_body = null):
speaking_animation.play("RESET")
func _reset():
pass
func _reset(_body):
speaking_animation.play("speaking")

View File

@ -1,43 +1,112 @@
[gd_scene load_steps=7 format=3 uid="uid://0sofmhrl358m"]
[gd_scene load_steps=12 format=3 uid="uid://0sofmhrl358m"]
[ext_resource type="Script" path="res://scene/entity/npc.gd" id="1_jegr2"]
[ext_resource type="SpriteFrames" uid="uid://bgbk80qo7mi7y" path="res://config/animation/ux_frames.tres" id="2_6xo6s"]
[ext_resource type="SpriteFrames" uid="uid://c3s8u4ifaucpj" path="res://config/animation/entity_sprite_frames.tres" id="3_1e8sl"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="3_kgq8p"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="4_jrmg5"]
[ext_resource type="Texture2D" uid="uid://gb3p6ry0bs5x" path="res://asset/art/ui/action_mark/说话标识1.png" id="5_foitt"]
[ext_resource type="Texture2D" uid="uid://dsofwe6knklyo" path="res://asset/art/ui/action_mark/说话标识2.png" id="6_2n6ge"]
[ext_resource type="Texture2D" uid="uid://blvlw8fgmmu8n" path="res://asset/art/ui/action_mark/说话标识3.png" id="7_afjxr"]
[sub_resource type="Animation" id="Animation_soodi"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("SpeakingSign2D/Sprite2D:texture")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 1,
"values": [null]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpeakingSign2D/Sprite2D:offset")
tracks/1/interp = 1
tracks/1/loop_wrap = true
tracks/1/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [Vector2(0, 0)]
}
[sub_resource type="Animation" id="Animation_a386j"]
resource_name = "speaking"
length = 1.5
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("SpeakingSign2D/Sprite2D:texture")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 0.5, 1),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 1,
"values": [ExtResource("5_foitt"), ExtResource("6_2n6ge"), ExtResource("7_afjxr")]
}
tracks/1/type = "value"
tracks/1/imported = false
tracks/1/enabled = true
tracks/1/path = NodePath("SpeakingSign2D/Sprite2D:offset")
tracks/1/interp = 2
tracks/1/loop_wrap = false
tracks/1/keys = {
"times": PackedFloat32Array(0, 1, 1.5),
"transitions": PackedFloat32Array(1, 1, 1),
"update": 0,
"values": [Vector2(60, 0), Vector2(0, 0), Vector2(0, 0)]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_pjqf1"]
_data = {
"RESET": SubResource("Animation_soodi"),
"speaking": SubResource("Animation_a386j")
}
[sub_resource type="RectangleShape2D" id="RectangleShape2D_4fuic"]
resource_local_to_scene = true
size = Vector2(33, 43)
size = Vector2(61, 112.75)
[node name="Npc" type="AnimatedSprite2D"]
sprite_frames = ExtResource("3_1e8sl")
animation = &"c02_李氏_idle"
animation = &"c02_张胖子_idle"
script = ExtResource("1_jegr2")
[node name="Sign" type="Sprite2D" parent="."]
[node name="SpeakingAnimationPlayer" type="AnimationPlayer" parent="."]
unique_name_in_owner = true
libraries = {
"": SubResource("AnimationLibrary_pjqf1")
}
[node name="PointLight2D" type="PointLight2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -72)
script = ExtResource("3_kgq8p")
[node name="PointLight2D" type="PointLight2D" parent="Sign"]
unique_name_in_owner = true
energy = 0.1
energy = 0.0
texture = ExtResource("4_jrmg5")
texture_scale = 0.1
[node name="SpeakingSignAnimation" type="AnimatedSprite2D" parent="."]
[node name="Sign" type="Sprite2D" parent="."]
unique_name_in_owner = true
position = Vector2(2, -72)
scale = Vector2(0.2, 0.2)
sprite_frames = ExtResource("2_6xo6s")
animation = &"sign"
autoplay = "sign"
script = ExtResource("3_kgq8p")
[node name="InteractArea2D" type="Area2D" parent="."]
[node name="SpeakingSign2D" type="Node2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -62)
scale = Vector2(0.1, 0.1)
[node name="Sprite2D" type="Sprite2D" parent="SpeakingSign2D"]
[node name="Area2D" type="Area2D" parent="."]
unique_name_in_owner = true
collision_layer = 0
[node name="CollisionShape2D" type="CollisionShape2D" parent="InteractArea2D"]
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
unique_name_in_owner = true
shape = SubResource("RectangleShape2D_4fuic")

View File

@ -12,23 +12,21 @@ extends Sprite2D
func _ready() -> void:
area2d.body_entered.connect(_reset)
area2d.body_exited.connect(_on_cancel)
area2d.body_entered.connect(sign_mark.activate)
area2d.body_exited.connect(sign_mark.disactivate)
sign_mark.interacted.connect(_on_interacted)
sign_mark.cancel.connect(_on_cancel)
if GlobalConfig.DEBUG:
var label = Label.new()
label.text = portal_name
label.name = "Label"
add_child(label)
# if GlobalConfig.DEBUG:
# var label = Label.new()
# label.text = portal_name
# label.name = "Label"
# add_child(label)
func _on_interacted() -> void:
# 传送
print("传送")
pass
func _on_cancel():
func _on_cancel(_body = null):
pass
func _reset():
func _reset(_body):
pass

View File

@ -4,7 +4,7 @@
[ext_resource type="Texture2D" uid="uid://dcafeofupga6j" path="res://asset/art/scene/c02/s06_院子回忆版/e_1014 开门.png" id="1_ynrqg"]
[ext_resource type="Texture2D" uid="uid://dbi1whlvfrt5k" path="res://asset/art/ui/action_mark/传送.png" id="2_ay30q"]
[ext_resource type="Script" path="res://scene/entity/ux/sign.gd" id="4_lu5q5"]
[ext_resource type="Texture2D" uid="uid://t526pexw4ng4" path="res://asset/art/neutral_point_light.webp" id="4_qn6pi"]
[ext_resource type="Resource" uid="uid://bbvtfv3xl1d6" path="res://config/audio/action/action_door_open.tres" id="5_7e0co"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_munml"]
resource_local_to_scene = true
@ -16,16 +16,19 @@ script = ExtResource("1_jyh6v")
[node name="Sign" type="Sprite2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -86)
position = Vector2(0, -73)
scale = Vector2(0.05, 0.05)
texture = ExtResource("2_ay30q")
script = ExtResource("4_lu5q5")
show_sign = null
audio_collection = ExtResource("5_7e0co")
[node name="PointLight2D" type="PointLight2D" parent="Sign"]
[node name="PointLight2D" type="PointLight2D" parent="."]
unique_name_in_owner = true
position = Vector2(0, -2.54313e-05)
energy = 0.1
texture = ExtResource("4_qn6pi")
position = Vector2(0, -86)
scale = Vector2(0.05, 0.05)
energy = 0.0
texture = ExtResource("2_ay30q")
texture_scale = 1.8
[node name="Area2D" type="Area2D" parent="."]

View File

@ -1,47 +1,115 @@
# @tool
extends Node2D
# @export var texture: Texture:
# set(val):
# texture = val
# sprite2d.texture = texture
# # @export var base_scale := Vector2.ONE:
# # set(val):
# # base_scale = val
# # sprite2d.scale = base_scale
@export var show_sign := true
@export var audio_collection: AudioStreamCollection
signal interacted
signal cancel
var activated = false
var base_scale: Vector2
var random_audio_player = RandomAudioStreamPlayer.new()
# 同时只能有一个物品被激活交互态,其他物品进入等待队列
static var occupied: NodePath
# 使用互斥锁保证线程安全
static var mutex = Mutex.new()
static var _pending_callables: Array[Callable]
var own_callable
var activated = false
var random_audio_player
# var sprite2d = Sprite2D.new()
var base_scale = Vector2.ONE
func _ready() -> void:
var point_light = get_node("./PointLight2D")
base_scale = scale
# layer = GlobalConfig.CANVAS_LAYER_FG
var point_light = get_node_or_null("../PointLight2D")
if point_light:
point_light.energy = 0.0
var area2d = get_node_or_null("../Area2D")
if area2d:
area2d.body_entered.connect(activate)
area2d.body_exited.connect(disactivate)
# # add child
# add_child(sprite2d)
# sprite2d.modulate.a = 0
# if Engine.is_editor_hint():
# sprite2d.modulate.a = 1
# _load_sprite()
modulate.a = 0
base_scale = scale
random_audio_player.audio_collections.append(audio_collection)
random_audio_player.bus = GlobalConfig.AUDIO_BUS_SFX
add_child(random_audio_player)
if audio_collection:
random_audio_player = RandomAudioStreamPlayer.new()
random_audio_player.audio_collections.append(audio_collection)
random_audio_player.bus = GlobalConfig.AUDIO_BUS_SFX
add_child(random_audio_player)
# func _load_sprite() -> void:
# sprite2d.texture = texture
# sprite2d.scale = base_scale
func activate(_body: Node2D) -> void:
# point_light.energy = 1.0
activated = true
var tween = create_tween()
tween.tween_property(self, "modulate:a", 1.0, 0.2)
var p_tween = tween.parallel()
p_tween.tween_property(self, "scale", base_scale * Vector2(1.2, 1.2), 0.3)
p_tween.tween_property(self, "scale", base_scale, 0.1)
mutex.lock()
if occupied:
own_callable = activate.bind(_body)
_pending_callables.append(own_callable)
else:
occupied = get_path()
activated = true
mutex.unlock()
if activated and show_sign:
var tween = create_tween()
tween.tween_property(self, "modulate:a", 1.0, 0.2)
var p_tween = tween.parallel()
p_tween.tween_property(self, "scale", base_scale * Vector2(1.2, 1.2), 0.3)
p_tween.tween_property(self, "scale", base_scale, 0.1)
func disactivate(_body: Node2D) -> void:
# point_light.energy = 0.0
activated = false
create_tween().tween_property(self, "modulate:a", 0.0, 0.2)
if _unoccupy():
if _pending_callables.size() > 0:
_pending_callables.pop_front().call()
# point_light.energy = 0.0
if show_sign:
create_tween().tween_property(self, "modulate:a", 0.0, 0.2)
func _input(event: InputEvent) -> void:
if activated:
if event.is_action_pressed("interact"):
interacted.emit()
if audio_collection:
if random_audio_player:
random_audio_player.play_random()
elif event.is_action_pressed("cancel"):
cancel.emit()
func _exit_tree() -> void:
if _unoccupy():
if _pending_callables.size() > 0:
_pending_callables.pop_front().call()
cancel.emit()
func _unoccupy() -> bool:
var is_occupied = false
mutex.lock()
if occupied == get_path():
occupied = ""
is_occupied = true
elif own_callable:
_pending_callables.erase(own_callable)
own_callable = null
mutex.unlock()
return is_occupied

View File

@ -1,10 +1,14 @@
[gd_scene load_steps=7 format=3 uid="uid://dayyx4jerj7io"]
[gd_scene load_steps=12 format=3 uid="uid://dayyx4jerj7io"]
[ext_resource type="Script" path="res://scene/ground/ground.gd" id="1_0vrlo"]
[ext_resource type="Script" path="res://config/deploy/scene_config.gd" id="2_bx7rv"]
[ext_resource type="Texture2D" uid="uid://cjyk6lbbdxiwf" path="res://asset/art/scene/c02/s06_院子回忆版/bg_院子1楼(黄昏有人).png" id="3_amw1x"]
[ext_resource type="PackedScene" uid="uid://jr1yd46wm5je" path="res://scene/entity/note.tscn" id="4_i8g3k"]
[ext_resource type="PackedScene" uid="uid://0sofmhrl358m" path="res://scene/entity/npc.tscn" id="4_n74on"]
[ext_resource type="Texture2D" uid="uid://by8h2yuqve7fw" path="res://asset/art/scene/c02/s06_院子回忆版/fg_有人.png" id="5_i5hii"]
[ext_resource type="PackedScene" uid="uid://61pis75a8fdq" path="res://scene/entity/portal.tscn" id="6_lalit"]
[ext_resource type="PackedScene" uid="uid://wyj4qdjyn4ql" path="res://scene/entity/inspectable.tscn" id="7_vhjr5"]
[ext_resource type="PackedScene" uid="uid://bnf3lkcbpx1ar" path="res://scene/entity/ambush.tscn" id="8_wig1g"]
[sub_resource type="Resource" id="Resource_6ux50"]
script = ExtResource("2_bx7rv")
@ -17,7 +21,11 @@ player_initial_position = Vector2(300, 186)
player_initial_direction = Vector2(1, -1)
player_movement_rect = Rect2(0, 0, 0, 0)
camera_rect = Rect2(0, -1000, 664, 2317)
footstep_type = "grass"
footstep_type = "concrete"
[sub_resource type="RectangleShape2D" id="RectangleShape2D_i13cb"]
resource_local_to_scene = true
size = Vector2(45, 100)
[node name="Ground" type="Node2D"]
script = ExtResource("1_0vrlo")
@ -33,8 +41,27 @@ offset = Vector2(0, -120)
[node name="DeployLayer" type="Node2D" parent="."]
unique_name_in_owner = true
[node name="Npc" parent="DeployLayer" instance=ExtResource("4_n74on")]
position = Vector2(465, 23)
[node name="Note" parent="DeployLayer" instance=ExtResource("4_i8g3k")]
position = Vector2(268, 8)
position = Vector2(278, 11)
notes = Array[String](["(门牌号: 1012)", "(似乎是用血来写的)"])
[node name="CollisionShape2D" parent="DeployLayer/Note/Area2D" index="0"]
position = Vector2(1, -6)
shape = SubResource("RectangleShape2D_i13cb")
[node name="Portal" parent="DeployLayer" instance=ExtResource("6_lalit")]
position = Vector2(213, 3)
scale = Vector2(1.02941, 1.06667)
[node name="Inspectable" parent="DeployLayer" instance=ExtResource("7_vhjr5")]
position = Vector2(381, -12)
[node name="Ambush" parent="DeployLayer" instance=ExtResource("8_wig1g")]
position = Vector2(567, 28)
hook_cg = "c02_胖子说话"
[node name="ParallaxForeground" type="ParallaxBackground" parent="."]
unique_name_in_owner = true
@ -47,7 +74,7 @@ motion_scale = Vector2(1.1, 1.1)
[node name="FGSprite2D" type="Sprite2D" parent="ParallaxForeground/FGParallaxLayer"]
unique_name_in_owner = true
position = Vector2(0, -120)
position = Vector2(-34, -118)
texture = ExtResource("5_i5hii")
centered = false
@ -77,3 +104,5 @@ grow_horizontal = 2
grow_vertical = 0
mouse_filter = 2
color = Color(0.0519829, 0.0179176, 0.00269875, 1)
[editable path="DeployLayer/Note"]

View File

@ -1,4 +1,4 @@
extends Node2D
class_name GroundLoader extends Node2D
@export var chapter := 2
@export var section := 1

View File

@ -1,15 +1,22 @@
[gd_scene load_steps=4 format=3 uid="uid://clxgkj80yin2"]
[gd_scene load_steps=5 format=3 uid="uid://clxgkj80yin2"]
[ext_resource type="Script" path="res://scene/ground/ground_loader.gd" id="1_6mjre"]
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="2_2ob1l"]
[ext_resource type="Script" path="res://config/audio/random_audio_stream_player.gd" id="3_vvkgn"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_51reu"]
resource_local_to_scene = true
size = Vector2(45, 100)
[node name="GroundLoader" type="Node2D"]
script = ExtResource("1_6mjre")
[node name="Ground" parent="." instance=ExtResource("2_2ob1l")]
unique_name_in_owner = true
[node name="CollisionShape2D" parent="Ground/DeployLayer/Note/Area2D" index="0"]
shape = SubResource("RectangleShape2D_51reu")
[node name="FootstepAudioStreamPlayer" type="AudioStreamPlayer" parent="."]
unique_name_in_owner = true
volume_db = -10.0
@ -19,3 +26,4 @@ script = ExtResource("3_vvkgn")
audio_collections = Array[Object]([])
[editable path="Ground"]
[editable path="Ground/DeployLayer/Note"]

View File

@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://scene/main.gd" id="1_pks84"]
[ext_resource type="PackedScene" uid="uid://3gk1gxwanw24" path="res://ui/vignette/vignette_shading.tscn" id="2_d1re1"]
[ext_resource type="PackedScene" uid="uid://dmkt1roqc4he7" path="res://scene/dialog/dialog_container.tscn" id="3_prpss"]
[ext_resource type="PackedScene" uid="uid://dmkt1roqc4he7" path="res://scene/dialog/dialog.tscn" id="3_prpss"]
[ext_resource type="PackedScene" uid="uid://dc778gsjfr3ky" path="res://scene/hud/prop_hud.tscn" id="4_t7gb2"]
[ext_resource type="PackedScene" uid="uid://5g07x6q7wwr1" path="res://scene/notification/notification.tscn" id="5_3gg5t"]
[ext_resource type="PackedScene" uid="uid://cekhj65axie0p" path="res://scene/popup/prop_inspector_2d.tscn" id="5_ux0rw"]
@ -24,7 +24,7 @@ scale = Vector2(0.24, 0.24)
mouse_filter = 0
metadata/_edit_use_anchors_ = true
[node name="DialogLayer" parent="UILayer" instance=ExtResource("3_prpss")]
[node name="Dialog" parent="UILayer" instance=ExtResource("3_prpss")]
offset_left = -230.0
offset_top = -70.0
offset_right = 230.0

View File

@ -13,6 +13,7 @@ enum MOVEMENT_STATUS {
}
@export var player_movement_rect := Rect2(50, -500, 1400, 1000)
@export var velocity_ratio := 1.0
@export var action_locked := false:
set(val):
action_locked = val
@ -53,9 +54,9 @@ func _ready() -> void:
func _on_footstep_timer_timeout():
# ground node is sibling of the player node.
var ground = get_node_or_null("../GroundLoader")
if ground:
ground.play_footstep_sound()
var ground_loader = SceneManager.get_ground_loader()
if ground_loader:
ground_loader.play_footstep_sound()
func _reset_face_direction() -> void:
@ -65,6 +66,7 @@ func _reset_face_direction() -> void:
func _process_action_lock() -> void:
# reset status to idle or stay
if action_locked:
velocity = Vector2.ZERO
if current_status == MOVEMENT_STATUS.WALKING or current_status == MOVEMENT_STATUS.RUNNING:
current_status = MOVEMENT_STATUS.IDLE
elif current_status == MOVEMENT_STATUS.LAYING_MOVING:
@ -169,7 +171,6 @@ func _physics_process(_delta: float) -> void:
if action_locked:
velocity = Vector2.ZERO
return
# Add the gravity.
#if not is_on_floor():
#velocity += get_gravity() * delta
@ -181,8 +182,8 @@ func _physics_process(_delta: float) -> void:
if _check_status(direction):
_play_animation()
var speed := _get_speed(direction) as Vector2
velocity.x = move_toward(velocity.x, speed.x, 300.0)
velocity.y = move_toward(velocity.y, speed.y, 300.0)
velocity.x = move_toward(velocity.x, speed.x, 300.0) * velocity_ratio
velocity.y = move_toward(velocity.y, speed.y, 300.0) * velocity_ratio
move_and_slide()
position = position.clamp(player_movement_rect.position, player_movement_rect.end)
_tweak_camera_marker()
@ -194,3 +195,30 @@ func _tweak_camera_marker():
var marker = get_node("./CameraFocusMarker") as Node2D
if marker:
marker.tweak_position(velocity, facing_direction)
var note_mutex = Mutex.new()
var note_pending_time = 0.0
var note_viewing = false
func check_note(note_time):
note_mutex.lock()
note_pending_time += note_time
if not note_viewing:
note_viewing = true
# velocity_ratio = 0.2
action_locked = true
get_tree().create_timer(note_time).timeout.connect(_check_slow)
note_mutex.unlock()
func _check_slow():
note_mutex.lock()
note_viewing = false
action_locked = false
# velocity_ratio = 1.0
note_mutex.unlock()
if note_pending_time:
note_pending_time = 0.0
check_note(note_pending_time)