鈎爪基礎功能
This commit is contained in:
parent
e3eeded054
commit
745342c35c
File diff suppressed because one or more lines are too long
|
|
@ -1,4 +1,4 @@
|
||||||
[gd_scene load_steps=12 format=4 uid="uid://bj2318o3y68x2"]
|
[gd_scene load_steps=20 format=4 uid="uid://bj2318o3y68x2"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_p0ota"]
|
[ext_resource type="PackedScene" uid="uid://1l06de041i40" path="res://_levels/l_level_1.tscn" id="1_p0ota"]
|
||||||
[ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_gslp7"]
|
[ext_resource type="PackedScene" uid="uid://cvqehvdjpoar4" path="res://_player/player_controller.tscn" id="2_gslp7"]
|
||||||
|
|
@ -8,6 +8,13 @@
|
||||||
[ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="6_6jw57"]
|
[ext_resource type="Script" uid="uid://7lml6d1t5xtq" path="res://addons/reedscene/prop/PropState.gd" id="6_6jw57"]
|
||||||
[ext_resource type="Script" uid="uid://cdvgq0xqdbagk" path="res://addons/reedscene/prop/ReedPropEffect.gd" id="7_2t6pm"]
|
[ext_resource type="Script" uid="uid://cdvgq0xqdbagk" path="res://addons/reedscene/prop/ReedPropEffect.gd" id="7_2t6pm"]
|
||||||
[ext_resource type="Script" uid="uid://jeybblac0kg2" path="res://addons/reedscene/prop/ReedTransition.gd" id="8_xkd7q"]
|
[ext_resource type="Script" uid="uid://jeybblac0kg2" path="res://addons/reedscene/prop/ReedTransition.gd" id="8_xkd7q"]
|
||||||
|
[ext_resource type="Script" uid="uid://bhexx6mj1xv3q" path="res://addons/phantom_camera/scripts/phantom_camera/phantom_camera_2d.gd" id="9_ady2r"]
|
||||||
|
[ext_resource type="Script" uid="uid://8umksf8e80fw" path="res://addons/phantom_camera/scripts/resources/tween_resource.gd" id="10_m16wo"]
|
||||||
|
[ext_resource type="Script" uid="uid://di41kt2tj34c2" path="res://addons/reedscene/prop/StateManager.gd" id="11_m16wo"]
|
||||||
|
[ext_resource type="Script" uid="uid://dsgl7lbyjsiif" path="res://addons/reedscene/act/ActManager.gd" id="12_xja44"]
|
||||||
|
[ext_resource type="Script" uid="uid://5e157vdk6175" path="res://addons/reedscene/scene/ReedScene.gd" id="13_2tycc"]
|
||||||
|
[ext_resource type="Script" uid="uid://pxjf5vst08eo" path="res://addons/reedscene/prop/PropManager.gd" id="14_3ihdv"]
|
||||||
|
[ext_resource type="Script" uid="uid://dn0ksjoswquf5" path="res://addons/reedscene/scene/SceneManager.gd" id="15_hc6q0"]
|
||||||
|
|
||||||
[sub_resource type="Resource" id="Resource_2t6pm"]
|
[sub_resource type="Resource" id="Resource_2t6pm"]
|
||||||
script = ExtResource("7_2t6pm")
|
script = ExtResource("7_2t6pm")
|
||||||
|
|
@ -32,6 +39,9 @@ value = null
|
||||||
func_name = &"door_open"
|
func_name = &"door_open"
|
||||||
metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
metadata/_custom_type_script = "uid://cdvgq0xqdbagk"
|
||||||
|
|
||||||
|
[sub_resource type="Resource" id="Resource_xja44"]
|
||||||
|
script = ExtResource("10_m16wo")
|
||||||
|
|
||||||
[node name="Game" type="Node2D"]
|
[node name="Game" type="Node2D"]
|
||||||
|
|
||||||
[node name="level_1" parent="." instance=ExtResource("1_p0ota")]
|
[node name="level_1" parent="." instance=ExtResource("1_p0ota")]
|
||||||
|
|
@ -49,6 +59,7 @@ position = Vector2(342, 176)
|
||||||
|
|
||||||
[node name="PropComponent" type="Node" parent="EventTriggerDoor"]
|
[node name="PropComponent" type="Node" parent="EventTriggerDoor"]
|
||||||
script = ExtResource("5_gslp7")
|
script = ExtResource("5_gslp7")
|
||||||
|
prop_id = 1
|
||||||
metadata/_custom_type_script = "uid://b4menkyub4ce7"
|
metadata/_custom_type_script = "uid://b4menkyub4ce7"
|
||||||
|
|
||||||
[node name="States" type="Node" parent="EventTriggerDoor/PropComponent"]
|
[node name="States" type="Node" parent="EventTriggerDoor/PropComponent"]
|
||||||
|
|
@ -70,3 +81,34 @@ script = ExtResource("8_xkd7q")
|
||||||
from_state_id = 0
|
from_state_id = 0
|
||||||
effects = Array[ExtResource("7_2t6pm")]([SubResource("Resource_xkd7q")])
|
effects = Array[ExtResource("7_2t6pm")]([SubResource("Resource_xkd7q")])
|
||||||
metadata/_custom_type_script = "uid://jeybblac0kg2"
|
metadata/_custom_type_script = "uid://jeybblac0kg2"
|
||||||
|
|
||||||
|
[node name="PhantomCamera2D" type="Node2D" parent="."]
|
||||||
|
script = ExtResource("9_ady2r")
|
||||||
|
tween_resource = SubResource("Resource_xja44")
|
||||||
|
metadata/_custom_type_script = "uid://bhexx6mj1xv3q"
|
||||||
|
|
||||||
|
[node name="PropComponent" type="Node" parent="PhantomCamera2D"]
|
||||||
|
script = ExtResource("5_gslp7")
|
||||||
|
prop_id = 0
|
||||||
|
metadata/_custom_type_script = "uid://b4menkyub4ce7"
|
||||||
|
|
||||||
|
[node name="States" type="Node" parent="PhantomCamera2D/PropComponent"]
|
||||||
|
script = ExtResource("11_m16wo")
|
||||||
|
|
||||||
|
[node name="[ID_0] Default" type="Node" parent="PhantomCamera2D/PropComponent/States"]
|
||||||
|
script = ExtResource("6_6jw57")
|
||||||
|
state_id = 0
|
||||||
|
|
||||||
|
[node name="ReedScene" type="Node2D" parent="."]
|
||||||
|
script = ExtResource("13_2tycc")
|
||||||
|
metadata/_custom_type_script = "uid://5e157vdk6175"
|
||||||
|
|
||||||
|
[node name="SceneManager" type="Node" parent="ReedScene" node_paths=PackedStringArray("TransitionNode")]
|
||||||
|
script = ExtResource("15_hc6q0")
|
||||||
|
TransitionNode = NodePath("Transition")
|
||||||
|
|
||||||
|
[node name="ActManager" type="Node" parent="ReedScene"]
|
||||||
|
script = ExtResource("12_xja44")
|
||||||
|
|
||||||
|
[node name="Props" type="Node2D" parent="ReedScene"]
|
||||||
|
script = ExtResource("14_3ihdv")
|
||||||
|
|
|
||||||
|
|
@ -124,7 +124,7 @@ unique_name_in_owner = true
|
||||||
script = ExtResource("16_xcbik")
|
script = ExtResource("16_xcbik")
|
||||||
grap_hook_shooting_time = 0.2
|
grap_hook_shooting_time = 0.2
|
||||||
|
|
||||||
[node name="Hooking" type="LimboState" parent="PlayerHSM/Normal/GrapHook"]
|
[node name="Grapping" type="LimboState" parent="PlayerHSM/Normal/GrapHook"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
|
||||||
[node name="Dash" type="LimboState" parent="PlayerHSM/Normal"]
|
[node name="Dash" type="LimboState" parent="PlayerHSM/Normal"]
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,7 @@ class_name Normal extends LimboHSM
|
||||||
|
|
||||||
@onready var grap_hook_state: LimboHSM = %GrapHook
|
@onready var grap_hook_state: LimboHSM = %GrapHook
|
||||||
@onready var hook_shooting_state: LimboState = %HookShooting
|
@onready var hook_shooting_state: LimboState = %HookShooting
|
||||||
@onready var hooking_state: LimboState = %Hooking
|
@onready var grapping_state: LimboState = %Grapping
|
||||||
|
|
||||||
|
|
||||||
func _setup() -> void:
|
func _setup() -> void:
|
||||||
self._init_trans()
|
self._init_trans()
|
||||||
|
|
@ -42,10 +41,11 @@ func _init_trans() -> void:
|
||||||
self.add_transition(on_wall_state,ground_state,&"exit_on_air")
|
self.add_transition(on_wall_state,ground_state,&"exit_on_air")
|
||||||
|
|
||||||
##用於處理鈎爪的State流轉
|
##用於處理鈎爪的State流轉
|
||||||
self.add_transition(ANYSTATE,grap_hook_state,&"want_to_grap_hook")
|
self.add_transition(ANYSTATE,grap_hook_state,&"want_to_grap_hook",_has_move_input)
|
||||||
self.add_transition(grap_hook_state,airbone_state,&"exit_on_ground")
|
self.add_transition(grap_hook_state,airbone_state,&"exit_on_ground")
|
||||||
self.add_transition(grap_hook_state,ground_state,&"exit_on_air")
|
self.add_transition(grap_hook_state,ground_state,&"exit_on_air")
|
||||||
|
|
||||||
|
|
||||||
func _update(delta: float) -> void:
|
func _update(delta: float) -> void:
|
||||||
process_direction()
|
process_direction()
|
||||||
|
|
||||||
|
|
@ -90,3 +90,6 @@ func _get_dash_exit_enter_state()->LimboState:
|
||||||
return ground_state
|
return ground_state
|
||||||
else:
|
else:
|
||||||
return airbone_state
|
return airbone_state
|
||||||
|
|
||||||
|
func _has_move_input() -> bool:
|
||||||
|
return agent.get_move_input() != Vector2.ZERO
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,6 @@ func _enter() -> void:
|
||||||
func _exit() -> void:
|
func _exit() -> void:
|
||||||
blackboard.set_var(&"is_dashing",false) ##BB里清除Dash状态
|
blackboard.set_var(&"is_dashing",false) ##BB里清除Dash状态
|
||||||
agent.locomotion_comp.enable_movement()
|
agent.locomotion_comp.enable_movement()
|
||||||
|
|
||||||
agent.locomotion_comp.can_dash = false
|
agent.locomotion_comp.can_dash = false
|
||||||
|
|
||||||
func _update(delta: float) -> void:
|
func _update(delta: float) -> void:
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,12 @@ extends LimboHSM
|
||||||
@onready var root: Normal = %Normal
|
@onready var root: Normal = %Normal
|
||||||
|
|
||||||
func _setup() -> void:
|
func _setup() -> void:
|
||||||
self.add_transition(root.hook_shooting_state,root.hooking_state,root.hook_shooting_state.EVENT_FINISHED)
|
self.add_transition(root.hook_shooting_state,root.grapping_state,root.hook_shooting_state.EVENT_FINISHED)
|
||||||
|
|
||||||
|
func _enter() -> void:
|
||||||
|
get_root().blackboard.set_var(&"is_hooking",true) ##BB里锁住Dash状态
|
||||||
|
|
||||||
func _exit() -> void:
|
func _exit() -> void:
|
||||||
|
get_root().blackboard.set_var(&"is_hooking",false) ##BB里锁住Dash状态
|
||||||
|
|
||||||
agent.locomotion_comp.enable_movement()
|
agent.locomotion_comp.enable_movement()
|
||||||
agent.spawn_hook_comp._current_grap_hook_inst._leave_rope()
|
|
||||||
|
|
|
||||||
|
|
@ -4,22 +4,35 @@ extends LimboState
|
||||||
|
|
||||||
var _timer: float
|
var _timer: float
|
||||||
|
|
||||||
|
func _setup() -> void:
|
||||||
|
self.add_event_handler(&"completed_grap_hook",_handle_hook_input_completed)
|
||||||
|
agent.spawn_hook_comp.hook_reach_finished.connect(_handle_hook_stretching_end)
|
||||||
|
|
||||||
func _enter() -> void:
|
func _enter() -> void:
|
||||||
agent.locomotion_comp.suspend_movement()
|
agent.locomotion_comp.suspend_movement()
|
||||||
agent.locomotion_comp.stop_dash(true)
|
agent.locomotion_comp.stop_dash(true)
|
||||||
|
|
||||||
agent.spawn_hook_comp.spawn_grap_hook_inst()
|
var d = agent.get_move_input() as Vector2
|
||||||
agent.spawn_hook_comp.grap_reach_target(grap_hook_shooting_time)
|
agent.spawn_hook_comp.spawn_grap_hook_inst(d)
|
||||||
|
|
||||||
_timer = grap_hook_shooting_time
|
|
||||||
|
|
||||||
func _update(delta: float) -> void:
|
func _update(delta: float) -> void:
|
||||||
|
pass
|
||||||
if _timer <= 0:
|
|
||||||
self.dispatch(self.EVENT_FINISHED)
|
|
||||||
|
|
||||||
_timer -= delta
|
|
||||||
|
|
||||||
func _exit() -> void:
|
func _exit() -> void:
|
||||||
#agent.locomotion_comp.enable_movement()
|
#agent.locomotion_comp.enable_movement()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
func _handle_hook_input_completed() -> bool:
|
||||||
|
return true
|
||||||
|
agent.spawn_hook_comp.suspend_hook_stretching(false)
|
||||||
|
return true
|
||||||
|
|
||||||
|
func _handle_hook_stretching_end(reach_end: bool,Anchor:Node2D) -> void:
|
||||||
|
|
||||||
|
##如果鈎爪沒有找到任何錨點,則直接退出
|
||||||
|
if not Anchor:
|
||||||
|
if agent.is_on_floor():
|
||||||
|
self.dispatch(&"exit_on_ground")
|
||||||
|
else:
|
||||||
|
self.dispatch(&"exit_on_air")
|
||||||
|
return
|
||||||
|
|
|
||||||
|
|
@ -237,7 +237,7 @@ script = ExtResource("6_68ewj")
|
||||||
[node name="RoomLeftPhantomCamera2D" type="Node2D" parent="." node_paths=PackedStringArray("follow_target")]
|
[node name="RoomLeftPhantomCamera2D" type="Node2D" parent="." node_paths=PackedStringArray("follow_target")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
top_level = true
|
top_level = true
|
||||||
position = Vector2(141, -91.205)
|
position = Vector2(66, -91.205)
|
||||||
script = ExtResource("6_2n5r1")
|
script = ExtResource("6_2n5r1")
|
||||||
priority = 5
|
priority = 5
|
||||||
follow_mode = 2
|
follow_mode = 2
|
||||||
|
|
@ -303,12 +303,12 @@ draw_limits = true
|
||||||
|
|
||||||
[node name="Camera2D" type="Camera2D" parent="."]
|
[node name="Camera2D" type="Camera2D" parent="."]
|
||||||
physics_interpolation_mode = 1
|
physics_interpolation_mode = 1
|
||||||
position = Vector2(141, -91.205)
|
position = Vector2(66, -91.205)
|
||||||
zoom = Vector2(2, 2)
|
zoom = Vector2(2, 2)
|
||||||
process_callback = 0
|
process_callback = 0
|
||||||
limit_left = -147
|
limit_left = -387
|
||||||
limit_top = -528
|
limit_top = -528
|
||||||
limit_right = 673
|
limit_right = 433
|
||||||
limit_bottom = 288
|
limit_bottom = 288
|
||||||
position_smoothing_speed = 10.0
|
position_smoothing_speed = 10.0
|
||||||
editor_draw_limits = true
|
editor_draw_limits = true
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ metadata/_edit_lock_ = true
|
||||||
[node name="MainCamera3D" type="Camera3D" parent="."]
|
[node name="MainCamera3D" type="Camera3D" parent="."]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
physics_interpolation_mode = 1
|
physics_interpolation_mode = 1
|
||||||
transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 2.5, 2)
|
transform = Transform3D(0.999889, 0, 0, 0, 0.707092, 0.707088, 0, -0.707092, 0.707088, 0, 2.5, 3.19136)
|
||||||
|
|
||||||
[node name="PhantomCameraHost" type="Node" parent="MainCamera3D"]
|
[node name="PhantomCameraHost" type="Node" parent="MainCamera3D"]
|
||||||
process_priority = 300
|
process_priority = 300
|
||||||
|
|
@ -136,7 +136,7 @@ script = ExtResource("2_d1opf")
|
||||||
|
|
||||||
[node name="PlayerPhantomCamera3D" type="Node3D" parent="." node_paths=PackedStringArray("follow_target")]
|
[node name="PlayerPhantomCamera3D" type="Node3D" parent="." node_paths=PackedStringArray("follow_target")]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
transform = Transform3D(0.999889, 0, 0, 0, 0.707092, 0.707088, 0, -0.707092, 0.707088, 0, 2.5, 2)
|
transform = Transform3D(0.999889, 0, 0, 0, 0.707092, 0.707088, 0, -0.707092, 0.707088, 0, 2.5, 3.19136)
|
||||||
top_level = true
|
top_level = true
|
||||||
script = ExtResource("3_4whss")
|
script = ExtResource("3_4whss")
|
||||||
priority = 3
|
priority = 3
|
||||||
|
|
@ -149,7 +149,7 @@ follow_offset = Vector3(0, 2, 2)
|
||||||
follow_damping = true
|
follow_damping = true
|
||||||
|
|
||||||
[node name="PlayerCharacterBody3D" parent="." instance=ExtResource("6_lr46m")]
|
[node name="PlayerCharacterBody3D" parent="." instance=ExtResource("6_lr46m")]
|
||||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0)
|
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 1.19136)
|
||||||
script = ExtResource("7_x1jex")
|
script = ExtResource("7_x1jex")
|
||||||
|
|
||||||
[node name="-------------------" type="Node" parent="."]
|
[node name="-------------------" type="Node" parent="."]
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,6 @@ extends Node2D
|
||||||
|
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
pcam_room_left.set_follow_offset(Vector2(0, -80))
|
|
||||||
pcam_room_right.set_follow_offset(Vector2(0, -80))
|
|
||||||
|
|
||||||
area_2d_room_left.body_entered.connect(_on_body_entered.bind(pcam_room_left))
|
area_2d_room_left.body_entered.connect(_on_body_entered.bind(pcam_room_left))
|
||||||
area_2d_room_centre.body_entered.connect(_on_body_entered.bind(pcam_room_centre))
|
area_2d_room_centre.body_entered.connect(_on_body_entered.bind(pcam_room_centre))
|
||||||
area_2d_room_right.body_entered.connect(_on_body_entered.bind(pcam_room_right))
|
area_2d_room_right.body_entered.connect(_on_body_entered.bind(pcam_room_right))
|
||||||
|
|
|
||||||
|
|
@ -144,6 +144,7 @@ func _physics_process(delta: float) -> void:
|
||||||
func _show_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void:
|
func _show_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void:
|
||||||
if body.is_class("TileMapLayer"): # TODO - Using string reference to support Godot 4.2
|
if body.is_class("TileMapLayer"): # TODO - Using string reference to support Godot 4.2
|
||||||
var tile_map := body
|
var tile_map := body
|
||||||
|
tile_map.physics_quadrant_size = 1
|
||||||
var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid)
|
var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid)
|
||||||
var cell_data: TileData = tile_map.get_cell_tile_data(tile_coords)
|
var cell_data: TileData = tile_map.get_cell_tile_data(tile_coords)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
[gd_resource type="ButtonGroup" load_steps=0 format=3 uid="uid://dfu0b8jbtyr1n"]
|
[gd_resource type="ButtonGroup" format=3 uid="uid://dfu0b8jbtyr1n"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
name="Phantom Camera"
|
name="Phantom Camera"
|
||||||
description="Control the movement and dynamically tween 2D & 3D cameras positions. Built for Godot 4. Inspired by Cinemachine."
|
description="Control the movement and dynamically tween 2D & 3D cameras positions. Built for Godot 4. Inspired by Cinemachine."
|
||||||
author="Marcus Skov"
|
author="Marcus Skov"
|
||||||
version="0.9.3.1"
|
version="0.9.4"
|
||||||
script="plugin.gd"
|
script="plugin.gd"
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
@tool
|
@tool
|
||||||
extends EditorNode3DGizmo
|
extends EditorNode3DGizmo
|
||||||
|
|
||||||
#var pcam_3d: PhantomCamera3D
|
var pcam_3d: PhantomCamera3D
|
||||||
|
|
||||||
func _redraw() -> void:
|
func _redraw() -> void:
|
||||||
clear()
|
clear()
|
||||||
|
|
@ -9,12 +9,12 @@ func _redraw() -> void:
|
||||||
var icon: Material = get_plugin().get_material(get_plugin().get_name(), self)
|
var icon: Material = get_plugin().get_material(get_plugin().get_name(), self)
|
||||||
add_unscaled_billboard(icon, 0.035)
|
add_unscaled_billboard(icon, 0.035)
|
||||||
|
|
||||||
var pcam_3d: PhantomCamera3D = get_node_3d()
|
pcam_3d = get_node_3d()
|
||||||
|
|
||||||
# if pcam_3d.is_following():
|
if pcam_3d.is_following() and pcam_3d.draw_follow_gizmo_line():
|
||||||
# _draw_target(pcam_3d, pcam_3d.get_follow_target_position(), "follow_target")
|
_draw_target(pcam_3d.get_follow_target_position(), "follow_target")
|
||||||
# if pcam_3d.is_looking_at():
|
if pcam_3d.is_looking() and pcam_3d.draw_look_at_gizmo_line():
|
||||||
# _draw_target(pcam_3d, pcam_3d.get_look_at_target_position(), "look_at_target")
|
_draw_target(pcam_3d.get_look_at_target_position(),"look_at_target")
|
||||||
|
|
||||||
if pcam_3d.is_active(): return
|
if pcam_3d.is_active(): return
|
||||||
|
|
||||||
|
|
@ -73,12 +73,13 @@ func _redraw() -> void:
|
||||||
add_lines(frustum_lines, frustum_material, false)
|
add_lines(frustum_lines, frustum_material, false)
|
||||||
|
|
||||||
|
|
||||||
func _draw_target(pcam_3d: Node3D, target_position: Vector3, type: String) -> void:
|
func _draw_target(target: Vector3, type: StringName) -> void:
|
||||||
var target_lines: PackedVector3Array = PackedVector3Array()
|
var target_lines: PackedVector3Array = PackedVector3Array()
|
||||||
var direction: Vector3 = target_position - pcam_3d.global_position
|
var direction: Vector3 = pcam_3d.global_position - target
|
||||||
var end_position: Vector3 = pcam_3d.global_basis.z * direction
|
var end_position: Vector3 = -direction * pcam_3d.quaternion
|
||||||
|
|
||||||
target_lines.push_back(Vector3.ZERO)
|
target_lines.push_back(Vector3.ZERO)
|
||||||
target_lines.push_back(end_position)
|
target_lines.push_back(end_position)
|
||||||
|
|
||||||
var target_material: StandardMaterial3D = get_plugin().get_material(type, self)
|
var target_material: StandardMaterial3D = get_plugin().get_material(type, self)
|
||||||
add_lines(target_lines, target_material, false)
|
add_lines(target_lines, target_material, false)
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ func _has_gizmo(spatial: Node3D) -> bool:
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
create_icon_material(gizmo_name, _icon_texture, false, Color.WHITE)
|
create_icon_material(gizmo_name, _icon_texture, false, Color.WHITE)
|
||||||
create_material("frustum", Color8(252, 127, 127, 255))
|
create_material("frustum", Color8(252, 127, 127, 255))
|
||||||
create_material("follow_target", Color8(185, 58, 89))
|
create_material("follow_target", Color8(248, 67, 47))
|
||||||
create_material("look_at_target", Color8(61, 207, 225))
|
create_material("look_at_target", Color8(61, 207, 225))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,8 @@ public static class PhantomCameraManager
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetPhantomCamera2Ds = "get_phantom_camera_2ds";
|
public static readonly StringName GetPhantomCamera2Ds = new("get_phantom_camera_2ds");
|
||||||
public const string GetPhantomCamera3Ds = "get_phantom_camera_3ds";
|
public static readonly StringName GetPhantomCamera3Ds = new("get_phantom_camera_3ds");
|
||||||
public const string GetPhantomCameraHosts = "get_phantom_camera_hosts";
|
public static readonly StringName GetPhantomCameraHosts = new("get_phantom_camera_hosts");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,14 +31,6 @@ public abstract class PhantomCamera
|
||||||
public event IsTweeningEventHandler? IsTweening;
|
public event IsTweeningEventHandler? IsTweening;
|
||||||
public event TweenCompletedEventHandler? TweenCompleted;
|
public event TweenCompletedEventHandler? TweenCompleted;
|
||||||
|
|
||||||
private readonly Callable _callableBecameActive;
|
|
||||||
private readonly Callable _callableBecameInactive;
|
|
||||||
private readonly Callable _callableFollowTargetChanged;
|
|
||||||
private readonly Callable _callableDeadZoneChanged;
|
|
||||||
private readonly Callable _callableTweenStarted;
|
|
||||||
private readonly Callable _callableIsTweening;
|
|
||||||
private readonly Callable _callableTweenCompleted;
|
|
||||||
|
|
||||||
public int Priority
|
public int Priority
|
||||||
{
|
{
|
||||||
get => (int)Node.Call(MethodName.GetPriority);
|
get => (int)Node.Call(MethodName.GetPriority);
|
||||||
|
|
@ -135,119 +127,108 @@ public abstract class PhantomCamera
|
||||||
{
|
{
|
||||||
Node = phantomCameraNode;
|
Node = phantomCameraNode;
|
||||||
|
|
||||||
_callableBecameActive = Callable.From(() => BecameActive?.Invoke());
|
var callableBecameActive = Callable.From(() => BecameActive?.Invoke());
|
||||||
_callableBecameInactive = Callable.From(() => BecameInactive?.Invoke());
|
var callableBecameInactive = Callable.From(() => BecameInactive?.Invoke());
|
||||||
_callableFollowTargetChanged = Callable.From(() => FollowTargetChanged?.Invoke());
|
var callableFollowTargetChanged = Callable.From(() => FollowTargetChanged?.Invoke());
|
||||||
_callableDeadZoneChanged = Callable.From(() => DeadZoneChanged?.Invoke());
|
var callableDeadZoneChanged = Callable.From(() => DeadZoneChanged?.Invoke());
|
||||||
_callableTweenStarted = Callable.From(() => TweenStarted?.Invoke());
|
var callableTweenStarted = Callable.From(() => TweenStarted?.Invoke());
|
||||||
_callableIsTweening = Callable.From(() => IsTweening?.Invoke());
|
var callableIsTweening = Callable.From(() => IsTweening?.Invoke());
|
||||||
_callableTweenCompleted = Callable.From(() => TweenCompleted?.Invoke());
|
var callableTweenCompleted = Callable.From(() => TweenCompleted?.Invoke());
|
||||||
|
|
||||||
Node.Connect(SignalName.BecameActive, _callableBecameActive);
|
Node.Connect(SignalName.BecameActive, callableBecameActive);
|
||||||
Node.Connect(SignalName.BecameInactive, _callableBecameInactive);
|
Node.Connect(SignalName.BecameInactive, callableBecameInactive);
|
||||||
Node.Connect(SignalName.FollowTargetChanged, _callableFollowTargetChanged);
|
Node.Connect(SignalName.FollowTargetChanged, callableFollowTargetChanged);
|
||||||
Node.Connect(SignalName.DeadZoneChanged, _callableDeadZoneChanged);
|
Node.Connect(SignalName.DeadZoneChanged, callableDeadZoneChanged);
|
||||||
Node.Connect(SignalName.TweenStarted, _callableTweenStarted);
|
Node.Connect(SignalName.TweenStarted, callableTweenStarted);
|
||||||
Node.Connect(SignalName.IsTweening, _callableIsTweening);
|
Node.Connect(SignalName.IsTweening, callableIsTweening);
|
||||||
Node.Connect(SignalName.TweenCompleted, _callableTweenCompleted);
|
Node.Connect(SignalName.TweenCompleted, callableTweenCompleted);
|
||||||
}
|
|
||||||
|
|
||||||
~PhantomCamera()
|
|
||||||
{
|
|
||||||
Node.Disconnect(SignalName.BecameActive, _callableBecameActive);
|
|
||||||
Node.Disconnect(SignalName.BecameInactive, _callableBecameInactive);
|
|
||||||
Node.Disconnect(SignalName.FollowTargetChanged, _callableFollowTargetChanged);
|
|
||||||
Node.Disconnect(SignalName.DeadZoneChanged, _callableDeadZoneChanged);
|
|
||||||
Node.Disconnect(SignalName.TweenStarted, _callableTweenStarted);
|
|
||||||
Node.Disconnect(SignalName.IsTweening, _callableIsTweening);
|
|
||||||
Node.Disconnect(SignalName.TweenCompleted, _callableTweenCompleted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetFollowMode = "get_follow_mode";
|
public static readonly StringName GetFollowMode = new("get_follow_mode");
|
||||||
public const string IsActive = "is_active";
|
public static readonly StringName IsActive = new("is_active");
|
||||||
|
|
||||||
public const string GetPriority = "get_priority";
|
public static readonly StringName GetPriority = new("get_priority");
|
||||||
public const string SetPriority = "set_priority";
|
public static readonly StringName SetPriority = new("set_priority");
|
||||||
|
|
||||||
public const string IsFollowing = "is_following";
|
public static readonly StringName IsFollowing = new("is_following");
|
||||||
|
|
||||||
public const string GetFollowTarget = "get_follow_target";
|
public static readonly StringName GetFollowTarget = new("get_follow_target");
|
||||||
public const string SetFollowTarget = "set_follow_target";
|
public static readonly StringName SetFollowTarget = new("set_follow_target");
|
||||||
|
|
||||||
public const string GetFollowTargets = "get_follow_targets";
|
public static readonly StringName GetFollowTargets = new("get_follow_targets");
|
||||||
public const string SetFollowTargets = "set_follow_targets";
|
public static readonly StringName SetFollowTargets = new("set_follow_targets");
|
||||||
|
|
||||||
public const string TeleportPosition = "teleport_position";
|
public static readonly StringName TeleportPosition = new("teleport_position");
|
||||||
|
|
||||||
public const string AppendFollowTargets = "append_follow_targets";
|
public static readonly StringName AppendFollowTargets = new("append_follow_targets");
|
||||||
public const string AppendFollowTargetsArray = "append_follow_targets_array";
|
public static readonly StringName AppendFollowTargetsArray = new("append_follow_targets_array");
|
||||||
public const string EraseFollowTargets = "erase_follow_targets";
|
public static readonly StringName EraseFollowTargets = new("erase_follow_targets");
|
||||||
|
|
||||||
public const string GetFollowPath = "get_follow_path";
|
public static readonly StringName GetFollowPath = new("get_follow_path");
|
||||||
public const string SetFollowPath = "set_follow_path";
|
public static readonly StringName SetFollowPath = new("set_follow_path");
|
||||||
|
|
||||||
public const string GetFollowOffset = "get_follow_offset";
|
public static readonly StringName GetFollowOffset = new("get_follow_offset");
|
||||||
public const string SetFollowOffset = "set_follow_offset";
|
public static readonly StringName SetFollowOffset = new("set_follow_offset");
|
||||||
|
|
||||||
public const string GetFollowDamping = "get_follow_damping";
|
public static readonly StringName GetFollowDamping = new("get_follow_damping");
|
||||||
public const string SetFollowDamping = "set_follow_damping";
|
public static readonly StringName SetFollowDamping = new("set_follow_damping");
|
||||||
|
|
||||||
public const string GetFollowDampingValue = "get_follow_damping_value";
|
public static readonly StringName GetFollowDampingValue = new("get_follow_damping_value");
|
||||||
public const string SetFollowDampingValue = "set_follow_damping_value";
|
public static readonly StringName SetFollowDampingValue = new("set_follow_damping_value");
|
||||||
|
|
||||||
public const string GetFollowAxisLock = "get_follow_axis_lock";
|
public static readonly StringName GetFollowAxisLock = new("get_follow_axis_lock");
|
||||||
public const string SetFollowAxisLock = "set_follow_axis_lock";
|
public static readonly StringName SetFollowAxisLock = new("set_follow_axis_lock");
|
||||||
|
|
||||||
public const string GetTweenResource = "get_tween_resource";
|
public static readonly StringName GetTweenResource = new("get_tween_resource");
|
||||||
public const string SetTweenResource = "set_tween_resource";
|
public static readonly StringName SetTweenResource = new("set_tween_resource");
|
||||||
|
|
||||||
public const string GetTweenSkip = "get_tween_skip";
|
public static readonly StringName GetTweenSkip = new("get_tween_skip");
|
||||||
public const string SetTweenSkip = "set_tween_skip";
|
public static readonly StringName SetTweenSkip = new("set_tween_skip");
|
||||||
|
|
||||||
public const string GetTweenDuration = "get_tween_duration";
|
public static readonly StringName GetTweenDuration = new("get_tween_duration");
|
||||||
public const string SetTweenDuration = "set_tween_duration";
|
public static readonly StringName SetTweenDuration = new("set_tween_duration");
|
||||||
|
|
||||||
public const string GetTweenTransition = "get_tween_transition";
|
public static readonly StringName GetTweenTransition = new("get_tween_transition");
|
||||||
public const string SetTweenTransition = "set_tween_transition";
|
public static readonly StringName SetTweenTransition = new("set_tween_transition");
|
||||||
|
|
||||||
public const string GetTweenEase = "get_tween_ease";
|
public static readonly StringName GetTweenEase = new("get_tween_ease");
|
||||||
public const string SetTweenEase = "set_tween_ease";
|
public static readonly StringName SetTweenEase = new("set_tween_ease");
|
||||||
|
|
||||||
public const string GetTweenOnLoad = "get_tween_on_load";
|
public static readonly StringName GetTweenOnLoad = new("get_tween_on_load");
|
||||||
public const string SetTweenOnLoad = "set_tween_on_load";
|
public static readonly StringName SetTweenOnLoad = new("set_tween_on_load");
|
||||||
|
|
||||||
public const string GetInactiveUpdateMode = "get_inactive_update_mode";
|
public static readonly StringName GetInactiveUpdateMode = new("get_inactive_update_mode");
|
||||||
public const string SetInactiveUpdateMode = "set_inactive_update_mode";
|
public static readonly StringName SetInactiveUpdateMode = new("set_inactive_update_mode");
|
||||||
|
|
||||||
public const string GetHostLayers = "get_host_layers";
|
public static readonly StringName GetHostLayers = new("get_host_layers");
|
||||||
public const string SetHostLayers = "set_host_layers";
|
public static readonly StringName SetHostLayers = new("set_host_layers");
|
||||||
public const string SetHostLayersValue = "set_host_layers_value";
|
public static readonly StringName SetHostLayersValue = new("set_host_layers_value");
|
||||||
|
|
||||||
public const string GetNoiseEmitterLayer = "get_noise_emitter_layer";
|
public static readonly StringName GetNoiseEmitterLayer = new("get_noise_emitter_layer");
|
||||||
public const string SetNoiseEmitterLayer = "set_noise_emitter_layer";
|
public static readonly StringName SetNoiseEmitterLayer = new("set_noise_emitter_layer");
|
||||||
|
|
||||||
public const string EmitNoise = "emit_noise";
|
public static readonly StringName EmitNoise = new("emit_noise");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PropertyName
|
public static class PropertyName
|
||||||
{
|
{
|
||||||
public const string DeadZoneWidth = "dead_zone_width";
|
public static readonly StringName DeadZoneWidth = new("dead_zone_width");
|
||||||
public const string DeadZoneHeight = "dead_zone_height";
|
public static readonly StringName DeadZoneHeight = new("dead_zone_height");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SignalName
|
public static class SignalName
|
||||||
{
|
{
|
||||||
public const string BecameActive = "became_active";
|
public static readonly StringName BecameActive = new("became_active");
|
||||||
public const string BecameInactive = "became_inactive";
|
public static readonly StringName BecameInactive = new("became_inactive");
|
||||||
public const string FollowTargetChanged = "follow_target_changed";
|
public static readonly StringName FollowTargetChanged = new("follow_target_changed");
|
||||||
public const string DeadZoneChanged = "dead_zone_changed";
|
public static readonly StringName DeadZoneChanged = new("dead_zone_changed");
|
||||||
public const string DeadZoneReached = "dead_zone_reached";
|
public static readonly StringName DeadZoneReached = new("dead_zone_reached");
|
||||||
public const string TweenStarted = "tween_started";
|
public static readonly StringName TweenStarted = new("tween_started");
|
||||||
public const string IsTweening = "is_tweening";
|
public static readonly StringName IsTweening = new("is_tweening");
|
||||||
public const string TweenCompleted = "tween_completed";
|
public static readonly StringName TweenCompleted = new("tween_completed");
|
||||||
public const string TweenInterrupted = "tween_interrupted";
|
public static readonly StringName TweenInterrupted = new("tween_interrupted");
|
||||||
public const string NoiseEmitted = "noise_emitted";
|
public static readonly StringName NoiseEmitted = new("noise_emitted");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,6 @@ public class PhantomCamera2D : PhantomCamera
|
||||||
public event DeadZoneReachedEventHandler? DeadZoneReached;
|
public event DeadZoneReachedEventHandler? DeadZoneReached;
|
||||||
public event NoiseEmittedEventHandler? NoiseEmitted;
|
public event NoiseEmittedEventHandler? NoiseEmitted;
|
||||||
|
|
||||||
private readonly Callable _callableTweenInterrupted;
|
|
||||||
private readonly Callable _callableDeadZoneReached;
|
|
||||||
private readonly Callable _callableNoiseEmitted;
|
|
||||||
|
|
||||||
public Node2D FollowTarget
|
public Node2D FollowTarget
|
||||||
{
|
{
|
||||||
get => (Node2D)Node2D.Call(PhantomCamera.MethodName.GetFollowTarget);
|
get => (Node2D)Node2D.Call(PhantomCamera.MethodName.GetFollowTarget);
|
||||||
|
|
@ -211,25 +207,15 @@ public class PhantomCamera2D : PhantomCamera
|
||||||
set => Node2D.Call(MethodName.SetLimitTarget, value);
|
set => Node2D.Call(MethodName.SetLimitTarget, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PhantomCamera2D FromScript(string path) => new(GD.Load<GDScript>(path).New().AsGodotObject());
|
|
||||||
public static PhantomCamera2D FromScript(GDScript script) => new(script.New().AsGodotObject());
|
|
||||||
|
|
||||||
public PhantomCamera2D(GodotObject phantomCameraNode) : base(phantomCameraNode)
|
public PhantomCamera2D(GodotObject phantomCameraNode) : base(phantomCameraNode)
|
||||||
{
|
{
|
||||||
_callableTweenInterrupted = Callable.From<Node2D>(pCam => TweenInterrupted?.Invoke(pCam));
|
var callableTweenInterrupted = Callable.From<Node2D>(pCam => TweenInterrupted?.Invoke(pCam));
|
||||||
_callableDeadZoneReached = Callable.From((Vector2 side) => DeadZoneReached?.Invoke(side));
|
var callableDeadZoneReached = Callable.From((Vector2 side) => DeadZoneReached?.Invoke(side));
|
||||||
_callableNoiseEmitted = Callable.From((Transform2D output) => NoiseEmitted?.Invoke(output));
|
var callableNoiseEmitted = Callable.From((Transform2D output) => NoiseEmitted?.Invoke(output));
|
||||||
|
|
||||||
Node2D.Connect(SignalName.TweenInterrupted, _callableTweenInterrupted);
|
Node2D.Connect(SignalName.TweenInterrupted, callableTweenInterrupted);
|
||||||
Node2D.Connect(SignalName.DeadZoneReached, _callableDeadZoneReached);
|
Node2D.Connect(SignalName.DeadZoneReached, callableDeadZoneReached);
|
||||||
Node2D.Connect(SignalName.NoiseEmitted, _callableNoiseEmitted);
|
Node2D.Connect(SignalName.NoiseEmitted, callableNoiseEmitted);
|
||||||
}
|
|
||||||
|
|
||||||
~PhantomCamera2D()
|
|
||||||
{
|
|
||||||
Node2D.Disconnect(SignalName.TweenInterrupted, _callableTweenInterrupted);
|
|
||||||
Node2D.Disconnect(SignalName.DeadZoneReached, _callableDeadZoneReached);
|
|
||||||
Node2D.Disconnect(SignalName.NoiseEmitted, _callableNoiseEmitted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetLimitTarget(TileMap tileMap)
|
public void SetLimitTarget(TileMap tileMap)
|
||||||
|
|
@ -265,64 +251,64 @@ public class PhantomCamera2D : PhantomCamera
|
||||||
|
|
||||||
public new static class MethodName
|
public new static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetZoom = "get_zoom";
|
public static readonly StringName GetZoom = new("get_zoom");
|
||||||
public const string SetZoom = "set_zoom";
|
public static readonly StringName SetZoom = new("set_zoom");
|
||||||
|
|
||||||
public const string GetSnapToPixel = "get_snap_to_pixel";
|
public static readonly StringName GetSnapToPixel = new("get_snap_to_pixel");
|
||||||
public const string SetSnapToPixel = "set_snap_to_pixel";
|
public static readonly StringName SetSnapToPixel = new("set_snap_to_pixel");
|
||||||
|
|
||||||
public const string GetRotateWithTarget = "get_rotate_with_target";
|
public static readonly StringName GetRotateWithTarget = new("get_rotate_with_target");
|
||||||
public const string SetRotateWithTarget = "set_rotate_with_target";
|
public static readonly StringName SetRotateWithTarget = new("set_rotate_with_target");
|
||||||
|
|
||||||
public const string GetRotationOffset = "get_rotation_offset";
|
public static readonly StringName GetRotationOffset = new("get_rotation_offset");
|
||||||
public const string SetRotationOffset = "set_rotation_offset";
|
public static readonly StringName SetRotationOffset = new("set_rotation_offset");
|
||||||
|
|
||||||
public const string GetRotationDamping = "get_rotation_damping";
|
public static readonly StringName GetRotationDamping = new("get_rotation_damping");
|
||||||
public const string SetRotationDamping = "set_rotation_damping";
|
public static readonly StringName SetRotationDamping = new("set_rotation_damping");
|
||||||
|
|
||||||
public const string GetRotationDampingValue = "get_rotation_damping_value";
|
public static readonly StringName GetRotationDampingValue = new("get_rotation_damping_value");
|
||||||
public const string SetRotationDampingValue = "set_rotation_damping_value";
|
public static readonly StringName SetRotationDampingValue = new("set_rotation_damping_value");
|
||||||
|
|
||||||
public const string GetLimit = "get_limit";
|
public static readonly StringName GetLimit = new("get_limit");
|
||||||
public const string SetLimit = "set_limit";
|
public static readonly StringName SetLimit = new("set_limit");
|
||||||
|
|
||||||
public const string GetLimitLeft = "get_limit_left";
|
public static readonly StringName GetLimitLeft = new("get_limit_left");
|
||||||
public const string SetLimitLeft = "set_limit_left";
|
public static readonly StringName SetLimitLeft = new("set_limit_left");
|
||||||
|
|
||||||
public const string GetLimitTop = "get_limit_top";
|
public static readonly StringName GetLimitTop = new("get_limit_top");
|
||||||
public const string SetLimitTop = "set_limit_top";
|
public static readonly StringName SetLimitTop = new("set_limit_top");
|
||||||
|
|
||||||
public const string GetLimitRight = "get_limit_right";
|
public static readonly StringName GetLimitRight = new("get_limit_right");
|
||||||
public const string SetLimitRight = "set_limit_right";
|
public static readonly StringName SetLimitRight = new("set_limit_right");
|
||||||
|
|
||||||
public const string GetLimitBottom = "get_limit_bottom";
|
public static readonly StringName GetLimitBottom = new("get_limit_bottom");
|
||||||
public const string SetLimitBottom = "set_limit_bottom";
|
public static readonly StringName SetLimitBottom = new("set_limit_bottom");
|
||||||
|
|
||||||
public const string GetLimitTarget = "get_limit_target";
|
public static readonly StringName GetLimitTarget = new("get_limit_target");
|
||||||
public const string SetLimitTarget = "set_limit_target";
|
public static readonly StringName SetLimitTarget = new("set_limit_target");
|
||||||
|
|
||||||
public const string GetLimitMargin = "get_limit_margin";
|
public static readonly StringName GetLimitMargin = new("get_limit_margin");
|
||||||
public const string SetLimitMargin = "set_limit_margin";
|
public static readonly StringName SetLimitMargin = new("set_limit_margin");
|
||||||
|
|
||||||
public const string GetAutoZoom = "get_auto_zoom";
|
public static readonly StringName GetAutoZoom = new("get_auto_zoom");
|
||||||
public const string SetAutoZoom = "set_auto_zoom";
|
public static readonly StringName SetAutoZoom = new("set_auto_zoom");
|
||||||
|
|
||||||
public const string GetAutoZoomMin = "get_auto_zoom_min";
|
public static readonly StringName GetAutoZoomMin = new("get_auto_zoom_min");
|
||||||
public const string SetAutoZoomMin = "set_auto_zoom_min";
|
public static readonly StringName SetAutoZoomMin = new("set_auto_zoom_min");
|
||||||
|
|
||||||
public const string GetAutoZoomMax = "get_auto_zoom_max";
|
public static readonly StringName GetAutoZoomMax = new("get_auto_zoom_max");
|
||||||
public const string SetAutoZoomMax = "set_auto_zoom_max";
|
public static readonly StringName SetAutoZoomMax = new("set_auto_zoom_max");
|
||||||
|
|
||||||
public const string GetAutoZoomMargin = "get_auto_zoom_margin";
|
public static readonly StringName GetAutoZoomMargin = new("get_auto_zoom_margin");
|
||||||
public const string SetAutoZoomMargin = "set_auto_zoom_margin";
|
public static readonly StringName SetAutoZoomMargin = new("set_auto_zoom_margin");
|
||||||
|
|
||||||
public const string GetNoise = "get_noise";
|
public static readonly StringName GetNoise = new("get_noise");
|
||||||
public const string SetNoise = "set_noise";
|
public static readonly StringName SetNoise = new("set_noise");
|
||||||
}
|
}
|
||||||
|
|
||||||
public new static class PropertyName
|
public new static class PropertyName
|
||||||
{
|
{
|
||||||
public const string DrawLimits = "draw_limits";
|
public static readonly StringName DrawLimits = new("draw_limits");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -69,7 +69,7 @@ public static class PhantomCamera3DExtensions
|
||||||
public static Vector3 GetThirdPersonRotationDegrees(this PhantomCamera3D pCam3D) =>
|
public static Vector3 GetThirdPersonRotationDegrees(this PhantomCamera3D pCam3D) =>
|
||||||
(Vector3)pCam3D.Node3D.Call(PhantomCamera3D.MethodName.GetThirdPersonRotationDegrees);
|
(Vector3)pCam3D.Node3D.Call(PhantomCamera3D.MethodName.GetThirdPersonRotationDegrees);
|
||||||
|
|
||||||
public static void SetThirdPersonDegrees(this PhantomCamera3D pCam3D, Vector3 rotation) =>
|
public static void SetThirdPersonRotationDegrees(this PhantomCamera3D pCam3D, Vector3 rotation) =>
|
||||||
pCam3D.Node3D.Call(PhantomCamera3D.MethodName.SetThirdPersonRotationDegrees, rotation);
|
pCam3D.Node3D.Call(PhantomCamera3D.MethodName.SetThirdPersonRotationDegrees, rotation);
|
||||||
|
|
||||||
public static Quaternion GetThirdPersonQuaternion(this PhantomCamera3D pCam3D) =>
|
public static Quaternion GetThirdPersonQuaternion(this PhantomCamera3D pCam3D) =>
|
||||||
|
|
@ -98,13 +98,6 @@ public class PhantomCamera3D : PhantomCamera
|
||||||
public event TweenInterruptedEventHandler? TweenInterrupted;
|
public event TweenInterruptedEventHandler? TweenInterrupted;
|
||||||
public event NoiseEmittedEventHandler? NoiseEmitted;
|
public event NoiseEmittedEventHandler? NoiseEmitted;
|
||||||
|
|
||||||
private readonly Callable _callableLookAtTargetChanged;
|
|
||||||
private readonly Callable _callableDeadZoneReached;
|
|
||||||
private readonly Callable _callableCamera3DResourceChanged;
|
|
||||||
private readonly Callable _callableCamera3DResourcePropertyChanged;
|
|
||||||
private readonly Callable _callableTweenInterrupted;
|
|
||||||
private readonly Callable _callableNoiseEmitted;
|
|
||||||
|
|
||||||
public Node3D FollowTarget
|
public Node3D FollowTarget
|
||||||
{
|
{
|
||||||
get => (Node3D)Node3D.Call(PhantomCamera.MethodName.GetFollowTarget);
|
get => (Node3D)Node3D.Call(PhantomCamera.MethodName.GetFollowTarget);
|
||||||
|
|
@ -256,18 +249,24 @@ public class PhantomCamera3D : PhantomCamera
|
||||||
set => Node3D.Call(MethodName.SetLookAtDampingValue, value);
|
set => Node3D.Call(MethodName.SetLookAtDampingValue, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Node3D Up
|
public Vector3 Up
|
||||||
{
|
{
|
||||||
get => (Node3D)Node3D.Call(MethodName.GetUp);
|
get => (Vector3)Node3D.Call(MethodName.GetUp);
|
||||||
set => Node3D.Call(MethodName.SetUp, value);
|
set => Node3D.Call(MethodName.SetUp, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector3 UpTarget
|
public Node3D UpTarget
|
||||||
{
|
{
|
||||||
get => (Vector3)Node3D.Call(MethodName.GetUpTarget);
|
get => (Node3D)Node3D.Call(MethodName.GetUpTarget);
|
||||||
set => Node3D.Call(MethodName.SetUpTarget, value);
|
set => Node3D.Call(MethodName.SetUpTarget, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int KeepAspect
|
||||||
|
{
|
||||||
|
get => (int)Node3D.Call(MethodName.GetKeepAspect);
|
||||||
|
set => Node3D.Call(MethodName.SetKeepAspect, value);
|
||||||
|
}
|
||||||
|
|
||||||
public int CullMask
|
public int CullMask
|
||||||
{
|
{
|
||||||
get => (int)Node3D.Call(MethodName.GetCullMask);
|
get => (int)Node3D.Call(MethodName.GetCullMask);
|
||||||
|
|
@ -342,152 +341,142 @@ public class PhantomCamera3D : PhantomCamera
|
||||||
|
|
||||||
public void EmitNoise(Transform3D transform) => Node3D.Call(PhantomCamera.MethodName.EmitNoise, transform);
|
public void EmitNoise(Transform3D transform) => Node3D.Call(PhantomCamera.MethodName.EmitNoise, transform);
|
||||||
|
|
||||||
public static PhantomCamera3D FromScript(string path) => new(GD.Load<GDScript>(path).New().AsGodotObject());
|
|
||||||
public static PhantomCamera3D FromScript(GDScript script) => new(script.New().AsGodotObject());
|
|
||||||
|
|
||||||
public PhantomCamera3D(GodotObject phantomCamera3DNode) : base(phantomCamera3DNode)
|
public PhantomCamera3D(GodotObject phantomCamera3DNode) : base(phantomCamera3DNode)
|
||||||
{
|
{
|
||||||
_callableLookAtTargetChanged = Callable.From(() => LookAtTargetChanged?.Invoke());
|
var callableLookAtTargetChanged = Callable.From(() => LookAtTargetChanged?.Invoke());
|
||||||
_callableDeadZoneReached = Callable.From(() => DeadZoneReached?.Invoke());
|
var callableDeadZoneReached = Callable.From(() => DeadZoneReached?.Invoke());
|
||||||
_callableCamera3DResourceChanged = Callable.From(() => Camera3DResourceChanged?.Invoke());
|
var callableCamera3DResourceChanged = Callable.From(() => Camera3DResourceChanged?.Invoke());
|
||||||
_callableCamera3DResourcePropertyChanged = Callable.From((StringName property, Variant value) =>
|
var callableCamera3DResourcePropertyChanged = Callable.From((StringName property, Variant value) =>
|
||||||
Camera3DResourcePropertyChanged?.Invoke(property, value));
|
Camera3DResourcePropertyChanged?.Invoke(property, value));
|
||||||
_callableTweenInterrupted = Callable.From<Node3D>(pCam => TweenInterrupted?.Invoke(pCam));
|
var callableTweenInterrupted = Callable.From<Node3D>(pCam => TweenInterrupted?.Invoke(pCam));
|
||||||
_callableNoiseEmitted = Callable.From((Transform3D output) => NoiseEmitted?.Invoke(output));
|
var callableNoiseEmitted = Callable.From((Transform3D output) => NoiseEmitted?.Invoke(output));
|
||||||
|
|
||||||
Node3D.Connect(SignalName.LookAtTargetChanged, _callableLookAtTargetChanged);
|
Node3D.Connect(SignalName.LookAtTargetChanged, callableLookAtTargetChanged);
|
||||||
Node3D.Connect(PhantomCamera.SignalName.DeadZoneReached, _callableDeadZoneReached);
|
Node3D.Connect(PhantomCamera.SignalName.DeadZoneReached, callableDeadZoneReached);
|
||||||
Node3D.Connect(SignalName.Camera3DResourceChanged, _callableCamera3DResourceChanged);
|
Node3D.Connect(SignalName.Camera3DResourceChanged, callableCamera3DResourceChanged);
|
||||||
Node3D.Connect(SignalName.Camera3DResourcePropertyChanged, _callableCamera3DResourcePropertyChanged);
|
Node3D.Connect(SignalName.Camera3DResourcePropertyChanged, callableCamera3DResourcePropertyChanged);
|
||||||
Node3D.Connect(PhantomCamera.SignalName.TweenInterrupted, _callableTweenInterrupted);
|
Node3D.Connect(PhantomCamera.SignalName.TweenInterrupted, callableTweenInterrupted);
|
||||||
Node3D.Connect(PhantomCamera.SignalName.NoiseEmitted, _callableNoiseEmitted);
|
Node3D.Connect(PhantomCamera.SignalName.NoiseEmitted, callableNoiseEmitted);
|
||||||
}
|
|
||||||
|
|
||||||
~PhantomCamera3D()
|
|
||||||
{
|
|
||||||
Node3D.Disconnect(SignalName.LookAtTargetChanged, _callableLookAtTargetChanged);
|
|
||||||
Node3D.Disconnect(PhantomCamera.SignalName.DeadZoneReached, _callableDeadZoneReached);
|
|
||||||
Node3D.Disconnect(SignalName.Camera3DResourceChanged, _callableCamera3DResourceChanged);
|
|
||||||
Node3D.Disconnect(SignalName.Camera3DResourcePropertyChanged, _callableCamera3DResourcePropertyChanged);
|
|
||||||
Node3D.Disconnect(PhantomCamera.SignalName.TweenInterrupted, _callableTweenInterrupted);
|
|
||||||
Node3D.Disconnect(PhantomCamera.SignalName.NoiseEmitted, _callableNoiseEmitted);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public new static class MethodName
|
public new static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetLookAtMode = "get_look_at_mode";
|
public static readonly StringName GetLookAtMode = new("get_look_at_mode");
|
||||||
|
|
||||||
public const string GetCamera3DResource = "get_camera_3d_resource";
|
public static readonly StringName GetCamera3DResource = new("get_camera_3d_resource");
|
||||||
public const string SetCamera3DResource = "set_camera_3d_resource";
|
public static readonly StringName SetCamera3DResource = new("set_camera_3d_resource");
|
||||||
|
|
||||||
public const string GetThirdPersonRotation = "get_third_person_rotation";
|
public static readonly StringName GetThirdPersonRotation = new("get_third_person_rotation");
|
||||||
public const string SetThirdPersonRotation = "set_third_person_rotation";
|
public static readonly StringName SetThirdPersonRotation = new("set_third_person_rotation");
|
||||||
|
|
||||||
public const string GetThirdPersonRotationDegrees = "get_third_person_rotation_degrees";
|
public static readonly StringName GetThirdPersonRotationDegrees = new("get_third_person_rotation_degrees");
|
||||||
public const string SetThirdPersonRotationDegrees = "set_third_person_rotation_degrees";
|
public static readonly StringName SetThirdPersonRotationDegrees = new("set_third_person_rotation_degrees");
|
||||||
|
|
||||||
public const string GetThirdPersonQuaternion = "get_third_person_quaternion";
|
public static readonly StringName GetThirdPersonQuaternion = new("get_third_person_quaternion");
|
||||||
public const string SetThirdPersonQuaternion = "set_third_person_quaternion";
|
public static readonly StringName SetThirdPersonQuaternion = new("set_third_person_quaternion");
|
||||||
|
|
||||||
public const string GetVerticalRotationOffset = "get_vertical_rotation_offset";
|
public static readonly StringName GetVerticalRotationOffset = new("get_vertical_rotation_offset");
|
||||||
public const string SetVerticalRotationOffset = "set_vertical_rotation_offset";
|
public static readonly StringName SetVerticalRotationOffset = new("set_vertical_rotation_offset");
|
||||||
|
|
||||||
public const string GetHorizontalRotationOffset = "get_horizontal_rotation_offset";
|
public static readonly StringName GetHorizontalRotationOffset = new("get_horizontal_rotation_offset");
|
||||||
public const string SetHorizontalRotationOffset = "set_horizontal_rotation_offset";
|
public static readonly StringName SetHorizontalRotationOffset = new("set_horizontal_rotation_offset");
|
||||||
|
|
||||||
public const string GetSpringLength = "get_spring_length";
|
public static readonly StringName GetSpringLength = new("get_spring_length");
|
||||||
public const string SetSpringLength = "set_spring_length";
|
public static readonly StringName SetSpringLength = new("set_spring_length");
|
||||||
|
|
||||||
public const string GetFollowDistance = "get_follow_distance";
|
public static readonly StringName GetFollowDistance = new("get_follow_distance");
|
||||||
public const string SetFollowDistance = "set_follow_distance";
|
public static readonly StringName SetFollowDistance = new("set_follow_distance");
|
||||||
|
|
||||||
public const string GetAutoFollowDistance = "get_auto_follow_distance";
|
public static readonly StringName GetAutoFollowDistance = new("get_auto_follow_distance");
|
||||||
public const string SetAutoFollowDistance = "set_auto_follow_distance";
|
public static readonly StringName SetAutoFollowDistance = new("set_auto_follow_distance");
|
||||||
|
|
||||||
public const string GetAutoFollowDistanceMin = "get_auto_follow_distance_min";
|
public static readonly StringName GetAutoFollowDistanceMin = new("get_auto_follow_distance_min");
|
||||||
public const string SetAutoFollowDistanceMin = "set_auto_follow_distance_min";
|
public static readonly StringName SetAutoFollowDistanceMin = new("set_auto_follow_distance_min");
|
||||||
|
|
||||||
public const string GetAutoFollowDistanceMax = "get_auto_follow_distance_max";
|
public static readonly StringName GetAutoFollowDistanceMax = new("get_auto_follow_distance_max");
|
||||||
public const string SetAutoFollowDistanceMax = "set_auto_follow_distance_max";
|
public static readonly StringName SetAutoFollowDistanceMax = new("set_auto_follow_distance_max");
|
||||||
|
|
||||||
public const string GetAutoFollowDistanceDivisor = "get_auto_follow_distance_divisor";
|
public static readonly StringName GetAutoFollowDistanceDivisor = new("get_auto_follow_distance_divisor");
|
||||||
public const string SetAutoFollowDistanceDivisor = "set_auto_follow_distance_divisor";
|
public static readonly StringName SetAutoFollowDistanceDivisor = new("set_auto_follow_distance_divisor");
|
||||||
|
|
||||||
public const string GetLookAtTarget = "get_look_at_target";
|
public static readonly StringName GetLookAtTarget = new("get_look_at_target");
|
||||||
public const string SetLookAtTarget = "set_look_at_target";
|
public static readonly StringName SetLookAtTarget = new("set_look_at_target");
|
||||||
|
|
||||||
public const string GetLookAtTargets = "get_look_at_targets";
|
public static readonly StringName GetLookAtTargets = new("get_look_at_targets");
|
||||||
public const string SetLookAtTargets = "set_look_at_targets";
|
public static readonly StringName SetLookAtTargets = new("set_look_at_targets");
|
||||||
|
|
||||||
public const string IsLooking = "is_looking";
|
public static readonly StringName IsLooking = new("is_looking");
|
||||||
|
|
||||||
public const string GetUp = "get_up";
|
public static readonly StringName GetUp = new("get_up");
|
||||||
public const string SetUp = "set_up";
|
public static readonly StringName SetUp = new("set_up");
|
||||||
|
|
||||||
public const string GetUpTarget = "get_up_target";
|
public static readonly StringName GetUpTarget = new("get_up_target");
|
||||||
public const string SetUpTarget = "set_up_target";
|
public static readonly StringName SetUpTarget = new("set_up_target");
|
||||||
|
|
||||||
public const string GetCollisionMask = "get_collision_mask";
|
public static readonly StringName GetCollisionMask = new("get_collision_mask");
|
||||||
public const string SetCollisionMask = "set_collision_mask";
|
public static readonly StringName SetCollisionMask = new("set_collision_mask");
|
||||||
|
|
||||||
public const string SetCollisionMaskValue = "set_collision_mask_value";
|
public static readonly StringName SetCollisionMaskValue = new("set_collision_mask_value");
|
||||||
|
|
||||||
public const string GetShape = "get_shape";
|
public static readonly StringName GetShape = new("get_shape");
|
||||||
public const string SetShape = "set_shape";
|
public static readonly StringName SetShape = new("set_shape");
|
||||||
|
|
||||||
public const string GetMargin = "get_margin";
|
public static readonly StringName GetMargin = new("get_margin");
|
||||||
public const string SetMargin = "set_margin";
|
public static readonly StringName SetMargin = new("set_margin");
|
||||||
|
|
||||||
public const string GetLookAtOffset = "get_look_at_offset";
|
public static readonly StringName GetLookAtOffset = new("get_look_at_offset");
|
||||||
public const string SetLookAtOffset = "set_look_at_offset";
|
public static readonly StringName SetLookAtOffset = new("set_look_at_offset");
|
||||||
|
|
||||||
public const string GetLookAtDamping = "get_look_at_damping";
|
public static readonly StringName GetLookAtDamping = new("get_look_at_damping");
|
||||||
public const string SetLookAtDamping = "set_look_at_damping";
|
public static readonly StringName SetLookAtDamping = new("set_look_at_damping");
|
||||||
|
|
||||||
public const string GetLookAtDampingValue = "get_look_at_damping_value";
|
public static readonly StringName GetLookAtDampingValue = new("get_look_at_damping_value");
|
||||||
public const string SetLookAtDampingValue = "set_look_at_damping_value";
|
public static readonly StringName SetLookAtDampingValue = new("set_look_at_damping_value");
|
||||||
|
|
||||||
public const string GetCullMask = "get_cull_mask";
|
public static readonly StringName GetKeepAspect = new("get_keep_aspect");
|
||||||
public const string SetCullMask = "set_cull_mask";
|
public static readonly StringName SetKeepAspect = new("set_keep_aspect");
|
||||||
|
|
||||||
public const string GetHOffset = "get_h_offset";
|
public static readonly StringName GetCullMask = new("get_cull_mask");
|
||||||
public const string SetHOffset = "set_h_offset";
|
public static readonly StringName SetCullMask = new("set_cull_mask");
|
||||||
|
|
||||||
public const string GetVOffset = "get_v_offset";
|
public static readonly StringName GetHOffset = new("get_h_offset");
|
||||||
public const string SetVOffset = "set_v_offset";
|
public static readonly StringName SetHOffset = new("set_h_offset");
|
||||||
|
|
||||||
public const string GetProjection = "get_projection";
|
public static readonly StringName GetVOffset = new("get_v_offset");
|
||||||
public const string SetProjection = "set_projection";
|
public static readonly StringName SetVOffset = new("set_v_offset");
|
||||||
|
|
||||||
public const string GetFov = "get_fov";
|
public static readonly StringName GetProjection = new("get_projection");
|
||||||
public const string SetFov = "set_fov";
|
public static readonly StringName SetProjection = new("set_projection");
|
||||||
|
|
||||||
public const string GetSize = "get_size";
|
public static readonly StringName GetFov = new("get_fov");
|
||||||
public const string SetSize = "set_size";
|
public static readonly StringName SetFov = new("set_fov");
|
||||||
|
|
||||||
public const string GetFrustumOffset = "get_frustum_offset";
|
public static readonly StringName GetSize = new("get_size");
|
||||||
public const string SetFrustumOffset = "set_frustum_offset";
|
public static readonly StringName SetSize = new("set_size");
|
||||||
|
|
||||||
public const string GetFar = "get_far";
|
public static readonly StringName GetFrustumOffset = new("get_frustum_offset");
|
||||||
public const string SetFar = "set_far";
|
public static readonly StringName SetFrustumOffset = new("set_frustum_offset");
|
||||||
|
|
||||||
public const string GetNear = "get_near";
|
public static readonly StringName GetFar = new("get_far");
|
||||||
public const string SetNear = "set_near";
|
public static readonly StringName SetFar = new("set_far");
|
||||||
|
|
||||||
public const string GetEnvironment = "get_environment";
|
public static readonly StringName GetNear = new("get_near");
|
||||||
public const string SetEnvironment = "set_environment";
|
public static readonly StringName SetNear = new("set_near");
|
||||||
|
|
||||||
public const string GetAttributes = "get_attributes";
|
public static readonly StringName GetEnvironment = new("get_environment");
|
||||||
public const string SetAttributes = "set_attributes";
|
public static readonly StringName SetEnvironment = new("set_environment");
|
||||||
|
|
||||||
public const string GetNoise = "get_noise";
|
public static readonly StringName GetAttributes = new("get_attributes");
|
||||||
public const string SetNoise = "set_noise";
|
public static readonly StringName SetAttributes = new("set_attributes");
|
||||||
|
|
||||||
|
public static readonly StringName GetNoise = new("get_noise");
|
||||||
|
public static readonly StringName SetNoise = new("set_noise");
|
||||||
}
|
}
|
||||||
|
|
||||||
public new static class SignalName
|
public new static class SignalName
|
||||||
{
|
{
|
||||||
public const string LookAtTargetChanged = "look_at_target_changed";
|
public static readonly StringName LookAtTargetChanged = new("look_at_target_changed");
|
||||||
public const string Camera3DResourceChanged = "camera_3d_resource_changed";
|
public static readonly StringName Camera3DResourceChanged = new("camera_3d_resource_changed");
|
||||||
public const string Camera3DResourcePropertyChanged = "camera_3d_resource_property_changed";
|
public static readonly StringName Camera3DResourcePropertyChanged = new("camera_3d_resource_property_changed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,29 +55,29 @@ public class PhantomCameraNoiseEmitter2D(GodotObject node)
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetNoise = "get_noise";
|
public static readonly StringName GetNoise = new("get_noise");
|
||||||
public const string SetNoise = "set_noise";
|
public static readonly StringName SetNoise = new("set_noise");
|
||||||
|
|
||||||
public const string GetContinuous = "get_continuous";
|
public static readonly StringName GetContinuous = new("get_continuous");
|
||||||
public const string SetContinuous = "set_continuous";
|
public static readonly StringName SetContinuous = new("set_continuous");
|
||||||
|
|
||||||
public const string GetGrowthTime = "get_growth_time";
|
public static readonly StringName GetGrowthTime = new("get_growth_time");
|
||||||
public const string SetGrowthTime = "set_growth_time";
|
public static readonly StringName SetGrowthTime = new("set_growth_time");
|
||||||
|
|
||||||
public const string GetDuration = "get_duration";
|
public static readonly StringName GetDuration = new("get_duration");
|
||||||
public const string SetDuration = "set_duration";
|
public static readonly StringName SetDuration = new("set_duration");
|
||||||
|
|
||||||
public const string GetDecayTime = "get_decay_time";
|
public static readonly StringName GetDecayTime = new("get_decay_time");
|
||||||
public const string SetDecayTime = "set_decay_time";
|
public static readonly StringName SetDecayTime = new("set_decay_time");
|
||||||
|
|
||||||
public const string GetNoiseEmitterLayer = "get_noise_emitter_layer";
|
public static readonly StringName GetNoiseEmitterLayer = new("get_noise_emitter_layer");
|
||||||
public const string SetNoiseEmitterLayer = "set_noise_emitter_layer";
|
public static readonly StringName SetNoiseEmitterLayer = new("set_noise_emitter_layer");
|
||||||
|
|
||||||
public const string SetNoiseEmitterLayerValue = "set_noise_emitter_layer_value";
|
public static readonly StringName SetNoiseEmitterLayerValue = new("set_noise_emitter_layer_value");
|
||||||
|
|
||||||
public const string Emit = "emit";
|
public static readonly StringName Emit = new("emit");
|
||||||
public const string IsEmitting = "is_emitting";
|
public static readonly StringName IsEmitting = new("is_emitting");
|
||||||
public const string Stop = "stop";
|
public static readonly StringName Stop = new("stop");
|
||||||
public const string Toggle = "toggle";
|
public static readonly StringName Toggle = new("toggle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,29 +55,29 @@ public class PhantomCameraNoiseEmitter3D(GodotObject node)
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetNoise = "get_noise";
|
public static readonly StringName GetNoise = new("get_noise");
|
||||||
public const string SetNoise = "set_noise";
|
public static readonly StringName SetNoise = new("set_noise");
|
||||||
|
|
||||||
public const string GetContinuous = "get_continuous";
|
public static readonly StringName GetContinuous = new("get_continuous");
|
||||||
public const string SetContinuous = "set_continuous";
|
public static readonly StringName SetContinuous = new("set_continuous");
|
||||||
|
|
||||||
public const string GetGrowthTime = "get_growth_time";
|
public static readonly StringName GetGrowthTime = new("get_growth_time");
|
||||||
public const string SetGrowthTime = "set_growth_time";
|
public static readonly StringName SetGrowthTime = new("set_growth_time");
|
||||||
|
|
||||||
public const string GetDuration = "get_duration";
|
public static readonly StringName GetDuration = new("get_duration");
|
||||||
public const string SetDuration = "set_duration";
|
public static readonly StringName SetDuration = new("set_duration");
|
||||||
|
|
||||||
public const string GetDecayTime = "get_decay_time";
|
public static readonly StringName GetDecayTime = new("get_decay_time");
|
||||||
public const string SetDecayTime = "set_decay_time";
|
public static readonly StringName SetDecayTime = new("set_decay_time");
|
||||||
|
|
||||||
public const string GetNoiseEmitterLayer = "get_noise_emitter_layer";
|
public static readonly StringName GetNoiseEmitterLayer = new("get_noise_emitter_layer");
|
||||||
public const string SetNoiseEmitterLayer = "set_noise_emitter_layer";
|
public static readonly StringName SetNoiseEmitterLayer = new("set_noise_emitter_layer");
|
||||||
|
|
||||||
public const string SetNoiseEmitterLayerValue = "set_noise_emitter_layer_value";
|
public static readonly StringName SetNoiseEmitterLayerValue = new("set_noise_emitter_layer_value");
|
||||||
|
|
||||||
public const string Emit = "emit";
|
public static readonly StringName Emit = new("emit");
|
||||||
public const string IsEmitting = "is_emitting";
|
public static readonly StringName IsEmitting = new("is_emitting");
|
||||||
public const string Stop = "stop";
|
public static readonly StringName Stop = new("stop");
|
||||||
public const string Toggle = "toggle";
|
public static readonly StringName Toggle = new("toggle");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -553,6 +553,8 @@ func _validate_property(property: Dictionary) -> void:
|
||||||
follow_mode == FollowMode.GLUED:
|
follow_mode == FollowMode.GLUED:
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
if property.name == "follow_damping_value" and not follow_damping:
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
###############
|
###############
|
||||||
## Follow Group
|
## Follow Group
|
||||||
|
|
@ -639,7 +641,6 @@ func _enter_tree() -> void:
|
||||||
_should_follow = false
|
_should_follow = false
|
||||||
FollowMode.GROUP:
|
FollowMode.GROUP:
|
||||||
_follow_targets_size_check()
|
_follow_targets_size_check()
|
||||||
_should_follow_checker()
|
|
||||||
_:
|
_:
|
||||||
_should_follow_checker()
|
_should_follow_checker()
|
||||||
|
|
||||||
|
|
@ -649,7 +650,6 @@ func _enter_tree() -> void:
|
||||||
update_limit_all_sides()
|
update_limit_all_sides()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
func _exit_tree() -> void:
|
func _exit_tree() -> void:
|
||||||
if not follow_mode == FollowMode.GROUP:
|
if not follow_mode == FollowMode.GROUP:
|
||||||
follow_targets = []
|
follow_targets = []
|
||||||
|
|
@ -659,19 +659,13 @@ func _exit_tree() -> void:
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if is_instance_valid(follow_target):
|
_transform_output = global_transform
|
||||||
_transform_output.origin = _get_target_position_offset()
|
|
||||||
else:
|
|
||||||
_transform_output = global_transform
|
|
||||||
|
|
||||||
_phantom_camera_manager.noise_2d_emitted.connect(_noise_emitted)
|
_phantom_camera_manager.noise_2d_emitted.connect(_noise_emitted)
|
||||||
|
|
||||||
if not Engine.is_editor_hint():
|
if not Engine.is_editor_hint():
|
||||||
_preview_noise = true
|
_preview_noise = true
|
||||||
|
|
||||||
if follow_mode == FollowMode.GROUP:
|
|
||||||
_follow_targets_size_check()
|
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
if _follow_target_physics_based or _is_active: return
|
if _follow_target_physics_based or _is_active: return
|
||||||
|
|
@ -804,6 +798,7 @@ func _set_follow_position() -> void:
|
||||||
dead_zone_reached.emit(Vector2(framed_side_offset.x, framed_side_offset.y))
|
dead_zone_reached.emit(Vector2(framed_side_offset.x, framed_side_offset.y))
|
||||||
else:
|
else:
|
||||||
_follow_framed_offset = _transform_output.origin - _get_target_position_offset()
|
_follow_framed_offset = _transform_output.origin - _get_target_position_offset()
|
||||||
|
_follow_target_position = global_position
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
_follow_target_position = _get_target_position_offset()
|
_follow_target_position = _get_target_position_offset()
|
||||||
|
|
@ -972,7 +967,7 @@ func _follow_targets_size_check() -> void:
|
||||||
_follow_targets = []
|
_follow_targets = []
|
||||||
for i in follow_targets.size():
|
for i in follow_targets.size():
|
||||||
if follow_targets[i] == null: continue
|
if follow_targets[i] == null: continue
|
||||||
if follow_targets[i].is_inside_tree():
|
if is_instance_valid(follow_targets[i]):
|
||||||
_follow_targets.append(follow_targets[i])
|
_follow_targets.append(follow_targets[i])
|
||||||
targets_size += 1
|
targets_size += 1
|
||||||
_follow_targets_single_target_index = i
|
_follow_targets_single_target_index = i
|
||||||
|
|
@ -1244,8 +1239,6 @@ func get_tween_ease() -> int:
|
||||||
func set_is_active(node, value) -> void:
|
func set_is_active(node, value) -> void:
|
||||||
if node is PhantomCameraHost:
|
if node is PhantomCameraHost:
|
||||||
_is_active = value
|
_is_active = value
|
||||||
if value:
|
|
||||||
_should_follow_checker()
|
|
||||||
queue_redraw()
|
queue_redraw()
|
||||||
else:
|
else:
|
||||||
printerr("PCams can only be set from the PhantomCameraHost")
|
printerr("PCams can only be set from the PhantomCameraHost")
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,8 @@ enum FollowLockAxis {
|
||||||
if follow_mode == FollowMode.NONE:
|
if follow_mode == FollowMode.NONE:
|
||||||
_should_follow = false
|
_should_follow = false
|
||||||
top_level = false
|
top_level = false
|
||||||
|
_draw_follow_gizmo_line = false
|
||||||
|
_check_draw_gizmo()
|
||||||
_is_parents_physics()
|
_is_parents_physics()
|
||||||
notify_property_list_changed()
|
notify_property_list_changed()
|
||||||
return
|
return
|
||||||
|
|
@ -182,6 +184,14 @@ enum FollowLockAxis {
|
||||||
_:
|
_:
|
||||||
_should_follow_checker()
|
_should_follow_checker()
|
||||||
|
|
||||||
|
## Disables Follow Gizmo Line for Follow Glued
|
||||||
|
if follow_mode == FollowMode.GLUED:
|
||||||
|
_draw_follow_gizmo_line = false
|
||||||
|
_check_draw_gizmo()
|
||||||
|
else:
|
||||||
|
if draw_follow_line: _draw_follow_gizmo_line = true
|
||||||
|
_check_draw_gizmo()
|
||||||
|
|
||||||
if follow_mode == FollowMode.FRAMED:
|
if follow_mode == FollowMode.FRAMED:
|
||||||
if _follow_framed_initial_set and follow_target:
|
if _follow_framed_initial_set and follow_target:
|
||||||
_follow_framed_initial_set = false
|
_follow_framed_initial_set = false
|
||||||
|
|
@ -237,14 +247,24 @@ enum FollowLockAxis {
|
||||||
|
|
||||||
if look_at_mode == LookAtMode.NONE:
|
if look_at_mode == LookAtMode.NONE:
|
||||||
_should_look_at = false
|
_should_look_at = false
|
||||||
|
_draw_look_at_gizmo_line = false
|
||||||
|
_check_draw_gizmo()
|
||||||
notify_property_list_changed()
|
notify_property_list_changed()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if look_at_mode == LookAtMode.MIMIC:
|
||||||
|
_draw_look_at_gizmo_line = false
|
||||||
|
_check_draw_gizmo()
|
||||||
|
else:
|
||||||
|
if draw_look_at_line: _draw_look_at_gizmo_line = true
|
||||||
|
_check_draw_gizmo()
|
||||||
|
|
||||||
if not look_at_mode == LookAtMode.GROUP:
|
if not look_at_mode == LookAtMode.GROUP:
|
||||||
if look_at_target is Node3D:
|
if look_at_target is Node3D:
|
||||||
_should_look_at = true
|
_should_look_at = true
|
||||||
else: # If Look At Group
|
else: # If Look At Group
|
||||||
_look_at_targets_size_check()
|
_look_at_targets_size_check()
|
||||||
|
|
||||||
notify_property_list_changed()
|
notify_property_list_changed()
|
||||||
|
|
||||||
## NOTE - Warning that Look At + Follow Mode hasn't been fully tested together yet
|
## NOTE - Warning that Look At + Follow Mode hasn't been fully tested together yet
|
||||||
|
|
@ -324,6 +344,12 @@ enum FollowLockAxis {
|
||||||
get = get_environment
|
get = get_environment
|
||||||
|
|
||||||
|
|
||||||
|
## Overrides the [member Camera3D.compositor] resource property.
|
||||||
|
@export var compositor: Compositor = null:
|
||||||
|
set = set_compositor,
|
||||||
|
get = get_compositor
|
||||||
|
|
||||||
|
|
||||||
@export_group("Follow Parameters")
|
@export_group("Follow Parameters")
|
||||||
## Offsets the [member follow_target] position.
|
## Offsets the [member follow_target] position.
|
||||||
@export var follow_offset: Vector3 = Vector3.ZERO:
|
@export var follow_offset: Vector3 = Vector3.ZERO:
|
||||||
|
|
@ -467,7 +493,6 @@ var horizontal_rotation_offset: float = 0:
|
||||||
set = set_margin,
|
set = set_margin,
|
||||||
get = get_margin
|
get = get_margin
|
||||||
|
|
||||||
|
|
||||||
@export_group("Look At Parameters")
|
@export_group("Look At Parameters")
|
||||||
## Offsets the target's [param Vector3] position that the
|
## Offsets the target's [param Vector3] position that the
|
||||||
## [param PhantomCamera3D] is looking at.
|
## [param PhantomCamera3D] is looking at.
|
||||||
|
|
@ -491,7 +516,6 @@ var horizontal_rotation_offset: float = 0:
|
||||||
get = get_look_at_damping_value
|
get = get_look_at_damping_value
|
||||||
|
|
||||||
@export_subgroup("Up Direction")
|
@export_subgroup("Up Direction")
|
||||||
|
|
||||||
## Defines the upward direction of the [param PhantomCamera3D] when [member look_at_mode] is set. [br]
|
## Defines the upward direction of the [param PhantomCamera3D] when [member look_at_mode] is set. [br]
|
||||||
## This value will be overriden if [member up_target] is defined.
|
## This value will be overriden if [member up_target] is defined.
|
||||||
@export var up: Vector3 = Vector3.UP:
|
@export var up: Vector3 = Vector3.UP:
|
||||||
|
|
@ -528,6 +552,67 @@ var horizontal_rotation_offset: float = 0:
|
||||||
set = set_noise_emitter_layer,
|
set = set_noise_emitter_layer,
|
||||||
get = get_noise_emitter_layer
|
get = get_noise_emitter_layer
|
||||||
|
|
||||||
|
|
||||||
|
@export_group("Editor")
|
||||||
|
@export_subgroup("Align with View")
|
||||||
|
## Adds an editor button that positions and rotates the [param PhantomCamera3D] to match the 3D viewport's transform.[br][br]
|
||||||
|
## This editor button is not visible if the [param PhantomCamera3D] is following [i]or[/i] looking at a target.[br][br]
|
||||||
|
## [b]Note[/b]: This is only functional in the editor.
|
||||||
|
@export_tool_button("Align Transform with View", "CenterView")
|
||||||
|
var align_transform_with_view: Callable = func():
|
||||||
|
var undo_redo: EditorUndoRedoManager = EditorInterface.get_editor_undo_redo()
|
||||||
|
var property: StringName = &"global_transform"
|
||||||
|
undo_redo.create_action("Aligned " + name + "'s transform with view")
|
||||||
|
undo_redo.add_do_property(self, property, EditorInterface.get_editor_viewport_3d(viewport_index).get_camera_3d().global_transform)
|
||||||
|
undo_redo.add_undo_property(self, property, global_transform)
|
||||||
|
undo_redo.commit_action()
|
||||||
|
|
||||||
|
## Adds an editor button that positions the [param PhantomCamera3D] to match the 3D viewport's position.[br][br]
|
||||||
|
## This editor button is not visible if the [param PhantomCamera3D] is following a target.[br][br]
|
||||||
|
## [b]Note[/b]: This is only functional in the editor.
|
||||||
|
@export_tool_button("Align Position with View", "ToolMove")
|
||||||
|
var align_position_with_view: Callable = func():
|
||||||
|
var undo_redo: EditorUndoRedoManager = EditorInterface.get_editor_undo_redo()
|
||||||
|
var property: StringName = &"global_position"
|
||||||
|
undo_redo.create_action("Aligned " + name + "'s position with view")
|
||||||
|
undo_redo.add_do_property(self, property, EditorInterface.get_editor_viewport_3d(viewport_index).get_camera_3d().global_position)
|
||||||
|
undo_redo.add_undo_property(self, property, global_position)
|
||||||
|
undo_redo.commit_action()
|
||||||
|
|
||||||
|
## Adds an editor button that rotates the [param PhantomCamera3D] to match the 3D viewport's rotation.[br][br]
|
||||||
|
## This editor button is not visible if the [param PhantomCamera3D] is looking at a target.[br][br]
|
||||||
|
## [b]Note[/b]: This is only functional in the editor.
|
||||||
|
@export_tool_button("Align Rotation with View", "ToolRotate")
|
||||||
|
var align_rotation_with_view: Callable = func():
|
||||||
|
var undo_redo: EditorUndoRedoManager = EditorInterface.get_editor_undo_redo()
|
||||||
|
var property: StringName = &"global_rotation"
|
||||||
|
undo_redo.create_action("Aligned " + name + "'s rotation with view")
|
||||||
|
undo_redo.add_do_property(self, property, EditorInterface.get_editor_viewport_3d(viewport_index).get_camera_3d().global_rotation)
|
||||||
|
undo_redo.add_undo_property(self, property, global_rotation)
|
||||||
|
undo_redo.commit_action()
|
||||||
|
|
||||||
|
## Change which viewport the alignment buttons should be based on.[br]
|
||||||
|
## [b]Note:[/b] If you are only using 1 viewport, keep the default value to 0.
|
||||||
|
@export_range(0, 3) var viewport_index: int = 0:
|
||||||
|
set(value):
|
||||||
|
viewport_index = value
|
||||||
|
get:
|
||||||
|
return viewport_index
|
||||||
|
|
||||||
|
|
||||||
|
@export_subgroup("Gizmo Line")
|
||||||
|
## Draws a line between the [param PhantomCamera3D] and its follow target position.[br]
|
||||||
|
## This is only drawn when a valid [member follow_target] or [member follow_targets] is set.
|
||||||
|
@export var draw_follow_line: bool = false:
|
||||||
|
set = set_draw_follow_line,
|
||||||
|
get = get_draw_follow_line
|
||||||
|
|
||||||
|
## Draws a line between the [param PhantomCamera3D] and its look at target position.[br]
|
||||||
|
## This is only drawn when a valid [member follow_target] or [member look_at_targets] is set.
|
||||||
|
@export var draw_look_at_line: bool = false:
|
||||||
|
set = set_draw_look_at_line,
|
||||||
|
get = get_draw_look_at_line
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Private Variables
|
#region Private Variables
|
||||||
|
|
@ -556,8 +641,8 @@ var _current_rotation: Vector3 = Vector3.ZERO
|
||||||
var _up: Vector3 = Vector3.UP
|
var _up: Vector3 = Vector3.UP
|
||||||
var _has_up_target: bool = false
|
var _has_up_target: bool = false
|
||||||
|
|
||||||
var _follow_target_position: Vector3 = Vector3.ZERO
|
var _follow_target_output_position: Vector3 = Vector3.ZERO
|
||||||
var _look_at_target_position: Vector3 = Vector3.ZERO
|
var _look_at_target_output_position: Vector3 = Vector3.ZERO
|
||||||
|
|
||||||
var _transform_output: Transform3D = Transform3D()
|
var _transform_output: Transform3D = Transform3D()
|
||||||
var _transform_noise: Transform3D = Transform3D()
|
var _transform_noise: Transform3D = Transform3D()
|
||||||
|
|
@ -574,6 +659,10 @@ var _has_follow_spring_arm: bool = false
|
||||||
|
|
||||||
var _has_noise_resource: bool = false
|
var _has_noise_resource: bool = false
|
||||||
|
|
||||||
|
var _draw_gizmo: bool = false
|
||||||
|
var _draw_follow_gizmo_line: bool = false
|
||||||
|
var _follow_target_position: Vector3 = Vector3.ZERO
|
||||||
|
var _draw_look_at_gizmo_line: bool = false
|
||||||
|
|
||||||
# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box.
|
# NOTE - Temp solution until Godot has better plugin autoload recognition out-of-the-box.
|
||||||
var _phantom_camera_manager: Node = null
|
var _phantom_camera_manager: Node = null
|
||||||
|
|
@ -634,11 +723,6 @@ func _validate_property(property: Dictionary) -> void:
|
||||||
################
|
################
|
||||||
## Follow Target
|
## Follow Target
|
||||||
################
|
################
|
||||||
if property.name == "follow_target":
|
|
||||||
if follow_mode == FollowMode.NONE or \
|
|
||||||
follow_mode == FollowMode.GROUP:
|
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
|
||||||
|
|
||||||
if property.name == "follow_path" and \
|
if property.name == "follow_path" and \
|
||||||
follow_mode != FollowMode.PATH:
|
follow_mode != FollowMode.PATH:
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
@ -648,10 +732,17 @@ func _validate_property(property: Dictionary) -> void:
|
||||||
####################
|
####################
|
||||||
if follow_mode == FollowMode.NONE:
|
if follow_mode == FollowMode.NONE:
|
||||||
match property.name:
|
match property.name:
|
||||||
|
"follow_target", \
|
||||||
"follow_offset", \
|
"follow_offset", \
|
||||||
"follow_damping", \
|
"follow_damping", \
|
||||||
"follow_damping_value", \
|
"follow_damping_value", \
|
||||||
"follow_axis_lock":
|
"follow_axis_lock", \
|
||||||
|
"draw_follow_line":
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
if follow_mode == FollowMode.GROUP:
|
||||||
|
match property.name:
|
||||||
|
"follow_target":
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
if property.name == "follow_offset":
|
if property.name == "follow_offset":
|
||||||
|
|
@ -716,19 +807,27 @@ func _validate_property(property: Dictionary) -> void:
|
||||||
##########
|
##########
|
||||||
## Look At
|
## Look At
|
||||||
##########
|
##########
|
||||||
if look_at_mode == LookAtMode.NONE:
|
match look_at_mode:
|
||||||
match property.name:
|
LookAtMode.NONE:
|
||||||
"look_at_target", \
|
match property.name:
|
||||||
"look_at_offset" , \
|
"look_at_target", \
|
||||||
"look_at_damping", \
|
"look_at_offset" , \
|
||||||
"look_at_damping_value", \
|
"look_at_damping", \
|
||||||
"up", \
|
"look_at_damping_value", \
|
||||||
"up_target":
|
"up", \
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
"up_target", \
|
||||||
elif look_at_mode == LookAtMode.GROUP:
|
"draw_look_at_line":
|
||||||
match property.name:
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
"look_at_target":
|
LookAtMode.MIMIC:
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
match property.name:
|
||||||
|
"draw_look_at_line":
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
LookAtMode.GROUP:
|
||||||
|
match property.name:
|
||||||
|
"look_at_target", \
|
||||||
|
"draw_look_at_line":
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
|
||||||
if property.name == "look_at_target":
|
if property.name == "look_at_target":
|
||||||
if look_at_mode == LookAtMode.NONE or \
|
if look_at_mode == LookAtMode.NONE or \
|
||||||
|
|
@ -746,6 +845,27 @@ func _validate_property(property: Dictionary) -> void:
|
||||||
if property.name == "up" and _has_up_target:
|
if property.name == "up" and _has_up_target:
|
||||||
property.usage = PROPERTY_USAGE_NO_EDITOR
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
##########################
|
||||||
|
## Align With Viewport
|
||||||
|
##########################
|
||||||
|
if property.name == 'align_transform_with_view' and \
|
||||||
|
(_should_look_at == true or _should_follow == true):
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
if property.name == 'align_position_with_view' and \
|
||||||
|
(
|
||||||
|
_should_follow == true or \
|
||||||
|
_should_follow == true and follow_mode == FollowMode.THIRD_PERSON
|
||||||
|
):
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
if property.name == 'align_rotation_with_view' and \
|
||||||
|
(
|
||||||
|
_should_look_at == true or \
|
||||||
|
_should_follow == true and follow_mode == FollowMode.THIRD_PERSON
|
||||||
|
):
|
||||||
|
property.usage = PROPERTY_USAGE_NO_EDITOR
|
||||||
|
|
||||||
|
|
||||||
func _enter_tree() -> void:
|
func _enter_tree() -> void:
|
||||||
_phantom_camera_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME)
|
_phantom_camera_manager = Engine.get_singleton(_constants.PCAM_MANAGER_NODE_NAME)
|
||||||
|
|
@ -824,18 +944,8 @@ func _ready():
|
||||||
_follow_spring_arm.global_rotation = initial_rotation
|
_follow_spring_arm.global_rotation = initial_rotation
|
||||||
_has_follow_spring_arm = true
|
_has_follow_spring_arm = true
|
||||||
top_level = false
|
top_level = false
|
||||||
FollowMode.FRAMED:
|
|
||||||
if not Engine.is_editor_hint():
|
|
||||||
if is_instance_valid(follow_target):
|
|
||||||
_follow_framed_offset = global_position - _get_target_position_offset()
|
|
||||||
_current_rotation = global_rotation
|
|
||||||
FollowMode.GROUP:
|
|
||||||
_follow_targets_size_check()
|
|
||||||
_:
|
_:
|
||||||
if is_instance_valid(follow_target):
|
_transform_output.origin = global_position
|
||||||
_transform_output.origin = _get_target_position_offset()
|
|
||||||
else:
|
|
||||||
_transform_output.origin = global_position
|
|
||||||
|
|
||||||
if not Engine.is_editor_hint():
|
if not Engine.is_editor_hint():
|
||||||
_preview_noise = true
|
_preview_noise = true
|
||||||
|
|
@ -848,6 +958,9 @@ func _ready():
|
||||||
|
|
||||||
|
|
||||||
func _process(delta: float) -> void:
|
func _process(delta: float) -> void:
|
||||||
|
if Engine.is_editor_hint() and _draw_gizmo:
|
||||||
|
update_gizmos()
|
||||||
|
|
||||||
if _follow_target_physics_based or _is_active: return
|
if _follow_target_physics_based or _is_active: return
|
||||||
process_logic(delta)
|
process_logic(delta)
|
||||||
|
|
||||||
|
|
@ -912,10 +1025,11 @@ func _look_at(delta: float) -> void:
|
||||||
func _set_follow_position() -> void:
|
func _set_follow_position() -> void:
|
||||||
match follow_mode:
|
match follow_mode:
|
||||||
FollowMode.GLUED:
|
FollowMode.GLUED:
|
||||||
_follow_target_position = follow_target.global_position
|
_follow_target_output_position = follow_target.global_position
|
||||||
|
|
||||||
FollowMode.SIMPLE:
|
FollowMode.SIMPLE:
|
||||||
_follow_target_position = _get_target_position_offset()
|
_follow_target_output_position = _get_target_position_offset()
|
||||||
|
_set_follow_gizmo_line_position(follow_target.global_position)
|
||||||
|
|
||||||
FollowMode.GROUP:
|
FollowMode.GROUP:
|
||||||
if _has_multiple_follow_targets:
|
if _has_multiple_follow_targets:
|
||||||
|
|
@ -929,13 +1043,15 @@ func _set_follow_position() -> void:
|
||||||
else:
|
else:
|
||||||
distance = follow_distance
|
distance = follow_distance
|
||||||
|
|
||||||
_follow_target_position = \
|
_follow_target_output_position = \
|
||||||
bounds.get_center() + \
|
bounds.get_center() + \
|
||||||
follow_offset + \
|
follow_offset + \
|
||||||
global_basis.z * \
|
global_basis.z * \
|
||||||
distance
|
distance
|
||||||
|
|
||||||
|
_set_follow_gizmo_line_position(bounds.get_center())
|
||||||
else:
|
else:
|
||||||
_follow_target_position = \
|
_follow_target_output_position = \
|
||||||
follow_targets[_follow_targets_single_target_index].global_position + \
|
follow_targets[_follow_targets_single_target_index].global_position + \
|
||||||
follow_offset + \
|
follow_offset + \
|
||||||
global_basis.z * \
|
global_basis.z * \
|
||||||
|
|
@ -943,15 +1059,16 @@ func _set_follow_position() -> void:
|
||||||
|
|
||||||
FollowMode.PATH:
|
FollowMode.PATH:
|
||||||
var path_position: Vector3 = follow_path.global_position
|
var path_position: Vector3 = follow_path.global_position
|
||||||
_follow_target_position = \
|
_follow_target_output_position = \
|
||||||
follow_path.curve.get_closest_point(
|
follow_path.curve.get_closest_point(
|
||||||
follow_target.global_position - path_position
|
follow_target.global_position - path_position
|
||||||
) + path_position
|
) + path_position
|
||||||
|
_set_follow_gizmo_line_position(follow_target.global_position)
|
||||||
|
|
||||||
FollowMode.FRAMED:
|
FollowMode.FRAMED:
|
||||||
if not Engine.is_editor_hint():
|
if not Engine.is_editor_hint():
|
||||||
if not _is_active:
|
if not _is_active:
|
||||||
_follow_target_position = _get_target_position_offset_distance()
|
_follow_target_output_position = _get_target_position_offset_distance()
|
||||||
else:
|
else:
|
||||||
viewport_position = get_viewport().get_camera_3d().unproject_position(_get_target_position_offset())
|
viewport_position = get_viewport().get_camera_3d().unproject_position(_get_target_position_offset())
|
||||||
var visible_rect_size: Vector2 = get_viewport().get_visible_rect().size
|
var visible_rect_size: Vector2 = get_viewport().get_visible_rect().size
|
||||||
|
|
@ -959,9 +1076,10 @@ func _set_follow_position() -> void:
|
||||||
_current_rotation = global_rotation
|
_current_rotation = global_rotation
|
||||||
|
|
||||||
if _current_rotation != global_rotation:
|
if _current_rotation != global_rotation:
|
||||||
_follow_target_position = _get_target_position_offset_distance()
|
_follow_target_output_position = _get_target_position_offset_distance()
|
||||||
|
|
||||||
if _get_framed_side_offset() != Vector2.ZERO:
|
if _get_framed_side_offset() != Vector2.ZERO:
|
||||||
|
var framed_offset: Vector2 = _get_framed_side_offset()
|
||||||
var target_position: Vector3 = _get_target_position_offset() + _follow_framed_offset
|
var target_position: Vector3 = _get_target_position_offset() + _follow_framed_offset
|
||||||
var glo_pos: Vector3
|
var glo_pos: Vector3
|
||||||
|
|
||||||
|
|
@ -969,13 +1087,13 @@ func _set_follow_position() -> void:
|
||||||
if dead_zone_width == 0 && dead_zone_height != 0:
|
if dead_zone_width == 0 && dead_zone_height != 0:
|
||||||
glo_pos = _get_target_position_offset_distance()
|
glo_pos = _get_target_position_offset_distance()
|
||||||
glo_pos.z = target_position.z
|
glo_pos.z = target_position.z
|
||||||
_follow_target_position = glo_pos
|
_follow_target_output_position = glo_pos
|
||||||
elif dead_zone_width != 0 && dead_zone_height == 0:
|
elif dead_zone_width != 0 && dead_zone_height == 0:
|
||||||
glo_pos = _get_target_position_offset_distance()
|
glo_pos = _get_target_position_offset_distance()
|
||||||
glo_pos.x = target_position.x
|
glo_pos.x = target_position.x
|
||||||
_follow_target_position = glo_pos
|
_follow_target_output_position = glo_pos
|
||||||
else:
|
else:
|
||||||
_follow_target_position = _get_target_position_offset_distance()
|
_follow_target_output_position = _get_target_position_offset_distance()
|
||||||
else:
|
else:
|
||||||
if _current_rotation != global_rotation:
|
if _current_rotation != global_rotation:
|
||||||
var opposite: float = sin(-global_rotation.x) * follow_distance + _get_target_position_offset().y
|
var opposite: float = sin(-global_rotation.x) * follow_distance + _get_target_position_offset().y
|
||||||
|
|
@ -983,17 +1101,35 @@ func _set_follow_position() -> void:
|
||||||
glo_pos.z = sqrt(pow(follow_distance, 2) - pow(opposite, 2)) + _get_target_position_offset().z
|
glo_pos.z = sqrt(pow(follow_distance, 2) - pow(opposite, 2)) + _get_target_position_offset().z
|
||||||
glo_pos.x = global_position.x
|
glo_pos.x = global_position.x
|
||||||
|
|
||||||
_follow_target_position = glo_pos
|
_follow_target_output_position = glo_pos
|
||||||
_current_rotation = global_rotation
|
_current_rotation = global_rotation
|
||||||
else:
|
else:
|
||||||
dead_zone_reached.emit()
|
dead_zone_reached.emit()
|
||||||
_follow_target_position = target_position
|
|
||||||
|
# FIX: Only move camera in the axis where dead zone is breached
|
||||||
|
var current_global_position: Vector3 = global_position
|
||||||
|
var current_offset: Vector3 = global_position - _get_target_position_offset()
|
||||||
|
|
||||||
|
# Update stored offset for non-breached axes
|
||||||
|
if framed_offset.x == 0:
|
||||||
|
_follow_framed_offset.x = current_offset.x
|
||||||
|
if framed_offset.y == 0:
|
||||||
|
_follow_framed_offset.z = current_offset.z
|
||||||
|
|
||||||
|
# Lock camera position on non-breached axes
|
||||||
|
if framed_offset.x == 0:
|
||||||
|
target_position.x = current_global_position.x
|
||||||
|
if framed_offset.y == 0:
|
||||||
|
target_position.z = current_global_position.z
|
||||||
|
|
||||||
|
_follow_target_output_position = target_position
|
||||||
else:
|
else:
|
||||||
_follow_framed_offset = global_position - _get_target_position_offset()
|
_follow_framed_offset = global_position - _get_target_position_offset()
|
||||||
|
_follow_target_position = global_position
|
||||||
_current_rotation = global_rotation
|
_current_rotation = global_rotation
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
_follow_target_position = _get_target_position_offset_distance()
|
_follow_target_output_position = _get_target_position_offset_distance()
|
||||||
var unprojected_position: Vector2 = _get_raw_unprojected_position()
|
var unprojected_position: Vector2 = _get_raw_unprojected_position()
|
||||||
var viewport_width: float = get_viewport().size.x
|
var viewport_width: float = get_viewport().size.x
|
||||||
var viewport_height: float = get_viewport().size.y
|
var viewport_height: float = get_viewport().size.y
|
||||||
|
|
@ -1013,32 +1149,36 @@ func _set_follow_position() -> void:
|
||||||
unprojected_position.y = (unprojected_position.y / aspect_ratio_scale + 1) / 2
|
unprojected_position.y = (unprojected_position.y / aspect_ratio_scale + 1) / 2
|
||||||
|
|
||||||
viewport_position = unprojected_position
|
viewport_position = unprojected_position
|
||||||
|
_set_follow_gizmo_line_position(follow_target.global_position)
|
||||||
|
|
||||||
FollowMode.THIRD_PERSON:
|
FollowMode.THIRD_PERSON:
|
||||||
if not Engine.is_editor_hint():
|
if not Engine.is_editor_hint():
|
||||||
if not _has_follow_spring_arm: return
|
if not _has_follow_spring_arm: return
|
||||||
_follow_target_position = _get_target_position_offset()
|
_follow_target_output_position = _get_target_position_offset()
|
||||||
else:
|
else:
|
||||||
_follow_target_position = _get_target_position_offset_distance_direction()
|
_follow_target_output_position = _get_target_position_offset_distance_direction()
|
||||||
|
# _follow_target_position = _get_target_position_offset_distance_direction()
|
||||||
|
_set_follow_gizmo_line_position(follow_target.global_position)
|
||||||
|
|
||||||
|
|
||||||
func _set_look_at_position() -> void:
|
func _set_look_at_position() -> void:
|
||||||
match look_at_mode:
|
match look_at_mode:
|
||||||
LookAtMode.MIMIC:
|
LookAtMode.MIMIC:
|
||||||
_look_at_target_position = global_position - look_at_target.global_basis.z
|
_look_at_target_output_position = global_position - look_at_target.global_basis.z
|
||||||
|
|
||||||
LookAtMode.SIMPLE:
|
LookAtMode.SIMPLE:
|
||||||
_look_at_target_position =look_at_target.global_position
|
_look_at_target_output_position = look_at_target.global_position
|
||||||
|
|
||||||
LookAtMode.GROUP:
|
LookAtMode.GROUP:
|
||||||
if not _has_multiple_look_at_targets:
|
if not _has_multiple_look_at_targets:
|
||||||
_look_at_target_position =look_at_targets[_look_at_targets_single_target_index].global_position
|
_look_at_target_output_position = look_at_targets[_look_at_targets_single_target_index].global_position
|
||||||
else:
|
else:
|
||||||
var bounds: AABB = AABB(look_at_targets[0].global_position, Vector3.ZERO)
|
var bounds: AABB = AABB(look_at_targets[0].global_position, Vector3.ZERO)
|
||||||
for node in look_at_targets:
|
for node in look_at_targets:
|
||||||
bounds = bounds.expand(node.global_position)
|
bounds = bounds.expand(node.global_position)
|
||||||
_look_at_target_position =bounds.get_center()
|
_look_at_target_output_position = bounds.get_center()
|
||||||
|
|
||||||
|
_look_at_target_output_position += look_at_offset
|
||||||
|
|
||||||
func _get_target_position_offset() -> Vector3:
|
func _get_target_position_offset() -> Vector3:
|
||||||
return follow_target.global_position + follow_offset
|
return follow_target.global_position + follow_offset
|
||||||
|
|
@ -1063,7 +1203,7 @@ func _set_follow_velocity(index: int, value: float) -> void:
|
||||||
func _interpolate_position(delta: float) -> void:
|
func _interpolate_position(delta: float) -> void:
|
||||||
if follow_damping and not Engine.is_editor_hint():
|
if follow_damping and not Engine.is_editor_hint():
|
||||||
if not _is_third_person_follow:
|
if not _is_third_person_follow:
|
||||||
global_position = _follow_target_position
|
global_position = _follow_target_output_position
|
||||||
for i in 3:
|
for i in 3:
|
||||||
_transform_output.origin[i] = _smooth_damp(
|
_transform_output.origin[i] = _smooth_damp(
|
||||||
global_position[i],
|
global_position[i],
|
||||||
|
|
@ -1077,7 +1217,7 @@ func _interpolate_position(delta: float) -> void:
|
||||||
else:
|
else:
|
||||||
for i in 3:
|
for i in 3:
|
||||||
_camera_target.global_position[i] = _smooth_damp(
|
_camera_target.global_position[i] = _smooth_damp(
|
||||||
_follow_target_position[i],
|
_follow_target_output_position[i],
|
||||||
_camera_target.global_position[i],
|
_camera_target.global_position[i],
|
||||||
i,
|
i,
|
||||||
_follow_velocity_ref[i],
|
_follow_velocity_ref[i],
|
||||||
|
|
@ -1087,7 +1227,7 @@ func _interpolate_position(delta: float) -> void:
|
||||||
)
|
)
|
||||||
_transform_output.origin = global_position
|
_transform_output.origin = global_position
|
||||||
else:
|
else:
|
||||||
_camera_target.global_position = _follow_target_position
|
_camera_target.global_position = _follow_target_output_position
|
||||||
_transform_output.origin = global_position
|
_transform_output.origin = global_position
|
||||||
|
|
||||||
if _is_third_person_follow:
|
if _is_third_person_follow:
|
||||||
|
|
@ -1098,7 +1238,7 @@ func _interpolate_position(delta: float) -> void:
|
||||||
|
|
||||||
|
|
||||||
func _look_at_target_quat(target_position: Vector3, up_direction: Vector3 = Vector3.UP) -> Quaternion:
|
func _look_at_target_quat(target_position: Vector3, up_direction: Vector3 = Vector3.UP) -> Quaternion:
|
||||||
var direction: Vector3 = -(target_position - global_position + look_at_offset).normalized()
|
var direction: Vector3 = -(target_position - global_position).normalized()
|
||||||
|
|
||||||
var basis_z: Vector3 = direction.normalized()
|
var basis_z: Vector3 = direction.normalized()
|
||||||
var basis_x: Vector3 = up_direction.cross(basis_z)
|
var basis_x: Vector3 = up_direction.cross(basis_z)
|
||||||
|
|
@ -1121,7 +1261,7 @@ func _interpolate_rotation(delta: float) -> void:
|
||||||
if _has_up_target:
|
if _has_up_target:
|
||||||
_up = up_target.global_basis.y
|
_up = up_target.global_basis.y
|
||||||
|
|
||||||
var target_quat: Quaternion = _look_at_target_quat(_look_at_target_position, _up)
|
var target_quat: Quaternion = _look_at_target_quat(_look_at_target_output_position, _up)
|
||||||
|
|
||||||
if look_at_damping:
|
if look_at_damping:
|
||||||
var current_quat: Quaternion = quaternion.normalized()
|
var current_quat: Quaternion = quaternion.normalized()
|
||||||
|
|
@ -1251,7 +1391,7 @@ func _follow_targets_size_check() -> void:
|
||||||
_follow_targets = []
|
_follow_targets = []
|
||||||
for i in follow_targets.size():
|
for i in follow_targets.size():
|
||||||
if follow_targets[i] == null: continue
|
if follow_targets[i] == null: continue
|
||||||
if follow_targets[i].is_inside_tree():
|
if is_instance_valid(follow_targets[i]):
|
||||||
_follow_targets.append(follow_targets[i])
|
_follow_targets.append(follow_targets[i])
|
||||||
targets_size += 1
|
targets_size += 1
|
||||||
_follow_targets_single_target_index = i
|
_follow_targets_single_target_index = i
|
||||||
|
|
@ -1357,6 +1497,18 @@ func _is_parents_physics(target: Node = self) -> void:
|
||||||
func _camera_resource_changed() -> void:
|
func _camera_resource_changed() -> void:
|
||||||
camera_3d_resource_changed.emit()
|
camera_3d_resource_changed.emit()
|
||||||
|
|
||||||
|
|
||||||
|
func _set_follow_gizmo_line_position(target_position: Vector3) -> void:
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
_follow_target_position = target_position
|
||||||
|
|
||||||
|
func _check_draw_gizmo() -> void:
|
||||||
|
if _draw_follow_gizmo_line or _draw_look_at_gizmo_line:
|
||||||
|
_draw_gizmo = true
|
||||||
|
else:
|
||||||
|
_draw_gizmo = false
|
||||||
|
update_gizmos()
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Public Functions
|
#region Public Functions
|
||||||
|
|
@ -1405,7 +1557,7 @@ func emit_noise(value: Transform3D) -> void:
|
||||||
func teleport_position() -> void:
|
func teleport_position() -> void:
|
||||||
_follow_velocity_ref = Vector3.ZERO
|
_follow_velocity_ref = Vector3.ZERO
|
||||||
_set_follow_position()
|
_set_follow_position()
|
||||||
_transform_output.origin = _follow_target_position
|
_transform_output.origin = _follow_target_output_position
|
||||||
_phantom_camera_manager.pcam_teleport.emit(self)
|
_phantom_camera_manager.pcam_teleport.emit(self)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1421,6 +1573,16 @@ func is_following() -> bool:
|
||||||
func is_looking() -> bool:
|
func is_looking() -> bool:
|
||||||
return _should_look_at
|
return _should_look_at
|
||||||
|
|
||||||
|
|
||||||
|
## Returns the world space coodinate of where the target the camera is following.
|
||||||
|
## In most cases, this is the
|
||||||
|
func get_follow_target_position() -> Vector3:
|
||||||
|
return _follow_target_position
|
||||||
|
|
||||||
|
## Returns the world space coordinate of where the camera is looking at.
|
||||||
|
func get_look_at_target_position() -> Vector3:
|
||||||
|
return _look_at_target_output_position
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1489,8 +1651,6 @@ func get_tween_ease() -> int:
|
||||||
func set_is_active(node: Node, value: bool) -> void:
|
func set_is_active(node: Node, value: bool) -> void:
|
||||||
if node is PhantomCameraHost:
|
if node is PhantomCameraHost:
|
||||||
_is_active = value
|
_is_active = value
|
||||||
if value:
|
|
||||||
_should_follow_checker()
|
|
||||||
else:
|
else:
|
||||||
printerr("PCams can only be set from the PhantomCameraHost")
|
printerr("PCams can only be set from the PhantomCameraHost")
|
||||||
## Gets current active state of the [param PhantomCamera3D].
|
## Gets current active state of the [param PhantomCamera3D].
|
||||||
|
|
@ -1553,6 +1713,7 @@ func set_follow_target(value: Node3D) -> void:
|
||||||
if not follow_mode == FollowMode.GROUP:
|
if not follow_mode == FollowMode.GROUP:
|
||||||
_should_follow = false
|
_should_follow = false
|
||||||
follow_target_changed.emit()
|
follow_target_changed.emit()
|
||||||
|
update_gizmos()
|
||||||
notify_property_list_changed()
|
notify_property_list_changed()
|
||||||
## Removes the current [Node3D] [member follow_target].
|
## Removes the current [Node3D] [member follow_target].
|
||||||
func erase_follow_target() -> void:
|
func erase_follow_target() -> void:
|
||||||
|
|
@ -1846,6 +2007,24 @@ func get_margin() -> float:
|
||||||
return margin
|
return margin
|
||||||
|
|
||||||
|
|
||||||
|
func set_draw_follow_line(value: bool) -> void:
|
||||||
|
draw_follow_line = value
|
||||||
|
_draw_follow_gizmo_line = value
|
||||||
|
_check_draw_gizmo()
|
||||||
|
|
||||||
|
func get_draw_follow_line() -> bool:
|
||||||
|
return draw_follow_line
|
||||||
|
|
||||||
|
|
||||||
|
func set_draw_look_at_line(value: bool) -> void:
|
||||||
|
draw_look_at_line = value
|
||||||
|
_draw_look_at_gizmo_line = value
|
||||||
|
_check_draw_gizmo()
|
||||||
|
|
||||||
|
func get_draw_look_at_line() -> bool:
|
||||||
|
return draw_look_at_line
|
||||||
|
|
||||||
|
|
||||||
## Gets the current [member look_at_mode]. Value is based on [enum LookAtMode]
|
## Gets the current [member look_at_mode]. Value is based on [enum LookAtMode]
|
||||||
## enum.[br]
|
## enum.[br]
|
||||||
## Note: To set a new [member look_at_mode], a separate [param PhantomCamera3D] should be used.
|
## Note: To set a new [member look_at_mode], a separate [param PhantomCamera3D] should be used.
|
||||||
|
|
@ -2136,6 +2315,15 @@ func set_attributes(value: CameraAttributes) -> void:
|
||||||
func get_attributes() -> CameraAttributes:
|
func get_attributes() -> CameraAttributes:
|
||||||
return attributes
|
return attributes
|
||||||
|
|
||||||
|
## Assigns a new [Compositor] resource to the [Camera3DResource].
|
||||||
|
func set_compositor(value: Compositor) -> void:
|
||||||
|
compositor = value
|
||||||
|
camera_3d_resource_property_changed.emit("compositor", value)
|
||||||
|
|
||||||
|
## Gets the [Camera3D.compositor] value assigned to the [Camera3DResource].
|
||||||
|
func get_compositor() -> Compositor:
|
||||||
|
return compositor
|
||||||
|
|
||||||
|
|
||||||
## Assigns a new [member Camera3D.h_offset] value.[br]
|
## Assigns a new [member Camera3D.h_offset] value.[br]
|
||||||
## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to
|
## [b]Note:[/b] This will override and make the [param Camera3DResource] unique to
|
||||||
|
|
@ -2269,6 +2457,15 @@ func get_follow_target_physics_based() -> bool:
|
||||||
return _follow_target_physics_based
|
return _follow_target_physics_based
|
||||||
|
|
||||||
|
|
||||||
|
## Used internally in phantom_camera_3d_gizmo.gd to check if the Follow line should be shown.
|
||||||
|
func draw_follow_gizmo_line() -> bool:
|
||||||
|
return _draw_follow_gizmo_line
|
||||||
|
|
||||||
|
## Used internally in phantom_camera_3d_gizmo.gd to check if the Look At line should be shown.
|
||||||
|
func draw_look_at_gizmo_line() -> bool:
|
||||||
|
return _draw_look_at_gizmo_line
|
||||||
|
|
||||||
|
|
||||||
func get_class() -> String:
|
func get_class() -> String:
|
||||||
return "PhantomCamera3D"
|
return "PhantomCamera3D"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,21 +23,15 @@ public class PhantomCameraHost()
|
||||||
{
|
{
|
||||||
public Node Node { get; } = null!;
|
public Node Node { get; } = null!;
|
||||||
|
|
||||||
public PhantomCameraHost(Node node) : this()
|
public PhantomCameraHost(GodotObject node) : this()
|
||||||
{
|
{
|
||||||
Node = node;
|
Node = node as Node;
|
||||||
|
|
||||||
_callablePCamBecameActive = Callable.From<Node>(pCam => PCamBecameActive?.Invoke(pCam));
|
var callablePCamBecameActive = Callable.From<Node>(pCam => PCamBecameActive?.Invoke(pCam));
|
||||||
_callablePCamBecameInactive = Callable.From<Node>(pCam => PCamBecameInactive?.Invoke(pCam));
|
var callablePCamBecameInactive = Callable.From<Node>(pCam => PCamBecameInactive?.Invoke(pCam));
|
||||||
|
|
||||||
Node.Connect(SignalName.PCamBecameActive, _callablePCamBecameActive);
|
Node.Connect(SignalName.PCamBecameActive, callablePCamBecameActive);
|
||||||
Node.Connect(SignalName.PCamBecameInactive, _callablePCamBecameInactive);
|
Node.Connect(SignalName.PCamBecameInactive, callablePCamBecameInactive);
|
||||||
}
|
|
||||||
|
|
||||||
~PhantomCameraHost()
|
|
||||||
{
|
|
||||||
Node.Disconnect(SignalName.PCamBecameActive, _callablePCamBecameActive);
|
|
||||||
Node.Disconnect(SignalName.PCamBecameInactive, _callablePCamBecameInactive);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public delegate void PCamBecameActiveEventHandler(Node pCam);
|
public delegate void PCamBecameActiveEventHandler(Node pCam);
|
||||||
|
|
@ -49,6 +43,7 @@ public class PhantomCameraHost()
|
||||||
|
|
||||||
private readonly Callable _callablePCamBecameActive;
|
private readonly Callable _callablePCamBecameActive;
|
||||||
private readonly Callable _callablePCamBecameInactive;
|
private readonly Callable _callablePCamBecameInactive;
|
||||||
|
|
||||||
// For when Godot becomes the minimum version
|
// For when Godot becomes the minimum version
|
||||||
// public InterpolationMode InterpolationMode
|
// public InterpolationMode InterpolationMode
|
||||||
// {
|
// {
|
||||||
|
|
@ -76,53 +71,43 @@ public class PhantomCameraHost()
|
||||||
|
|
||||||
public bool TriggerPhantomCameraTween => (bool)Node.Call(MethodName.GetTriggerPhantomCameraTween);
|
public bool TriggerPhantomCameraTween => (bool)Node.Call(MethodName.GetTriggerPhantomCameraTween);
|
||||||
|
|
||||||
public ActivePhantomCameraQueryResult? GetActivePhantomCamera()
|
public PhantomCamera? GetActivePhantomCamera()
|
||||||
{
|
{
|
||||||
var result = Node.Call(MethodName.GetActivePhantomCamera);
|
var result = Node.Call(MethodName.GetActivePhantomCamera);
|
||||||
return result.VariantType == Variant.Type.Nil ? null : new ActivePhantomCameraQueryResult(result.AsGodotObject());
|
|
||||||
|
if (result.Obj is Node2D node2D)
|
||||||
|
{
|
||||||
|
return new PhantomCamera2D(node2D);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Obj is Node3D node3D)
|
||||||
|
{
|
||||||
|
return new PhantomCamera3D(node3D);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class PropertyName
|
public static class PropertyName
|
||||||
{
|
{
|
||||||
public const string Camera2D = "camera_2d";
|
public static readonly StringName Camera2D = new("camera_2d");
|
||||||
public const string Camera3D = "camera_3d";
|
public static readonly StringName Camera3D = new("camera_3d");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetActivePhantomCamera = "get_active_pcam";
|
public static readonly StringName GetActivePhantomCamera = new("get_active_pcam");
|
||||||
public const string GetTriggerPhantomCameraTween = "get_trigger_pcam_tween";
|
public static readonly StringName GetTriggerPhantomCameraTween = new("get_trigger_pcam_tween");
|
||||||
|
|
||||||
public const string GetInterpolationMode = "get_interpolation_mode";
|
public static readonly StringName GetInterpolationMode = new("get_interpolation_mode");
|
||||||
public const string SetInterpolationMode = "set_interpolation_mode";
|
public static readonly StringName SetInterpolationMode = new("set_interpolation_mode");
|
||||||
|
|
||||||
public const string SetHostLayersValue = "set_host_layers_value";
|
public static readonly StringName SetHostLayersValue = new("set_host_layers_value");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class SignalName
|
public static class SignalName
|
||||||
{
|
{
|
||||||
public const string PCamBecameActive = "pcam_became_active";
|
public static readonly StringName PCamBecameActive = new("pcam_became_active");
|
||||||
public const string PCamBecameInactive = "pcam_became_inactive";
|
public static readonly StringName PCamBecameInactive = new("pcam_became_inactive");
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public class ActivePhantomCameraQueryResult(GodotObject godotObject)
|
|
||||||
{
|
|
||||||
public bool Is2D => godotObject.IsClass("Node2D") || ((Node)godotObject).Name.ToString().Contains("PhantomCamera2D")
|
|
||||||
|| ((Node)godotObject).Name.ToString().Contains("PCam2D")
|
|
||||||
|| ((Node)godotObject).Name.ToString().Contains("2D");
|
|
||||||
|
|
||||||
public bool Is3D => godotObject.IsClass("Node3D") || ((Node)godotObject).Name.ToString().Contains("PhantomCamera3D")
|
|
||||||
|| ((Node)godotObject).Name.ToString().Contains("PCam3D")
|
|
||||||
|| ((Node)godotObject).Name.ToString().Contains("3D");
|
|
||||||
|
|
||||||
public PhantomCamera2D? AsPhantomCamera2D()
|
|
||||||
{
|
|
||||||
return Is2D ? new PhantomCamera2D(godotObject) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PhantomCamera3D? AsPhantomCamera3D()
|
|
||||||
{
|
|
||||||
return Is3D ? new PhantomCamera3D(godotObject) : null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,7 @@ var _cam_attribute_changed: bool = false
|
||||||
var _cam_attribute_assigned: bool = false
|
var _cam_attribute_assigned: bool = false
|
||||||
|
|
||||||
#region CameraAttributes
|
#region CameraAttributes
|
||||||
|
|
||||||
var _prev_cam_auto_exposure_scale: float = 0.4
|
var _prev_cam_auto_exposure_scale: float = 0.4
|
||||||
var _cam_auto_exposure_scale_changed: bool = false
|
var _cam_auto_exposure_scale_changed: bool = false
|
||||||
|
|
||||||
|
|
@ -137,9 +138,11 @@ var _cam_dof_blur_near_distance_changed: bool = false
|
||||||
var _cam_dof_blur_near_transition_default: float = 1
|
var _cam_dof_blur_near_transition_default: float = 1
|
||||||
var _prev_cam_dof_blur_near_transition: float = _cam_dof_blur_near_transition_default
|
var _prev_cam_dof_blur_near_transition: float = _cam_dof_blur_near_transition_default
|
||||||
var _cam_dof_blur_near_transition_changed: bool = false
|
var _cam_dof_blur_near_transition_changed: bool = false
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region CameraAttributesPhysical
|
#region CameraAttributesPhysical
|
||||||
|
|
||||||
var _prev_cam_exposure_min_exposure_value: float = 10.0
|
var _prev_cam_exposure_min_exposure_value: float = 10.0
|
||||||
var _cam_exposure_min_exposure_value_changed: bool = false
|
var _cam_exposure_min_exposure_value_changed: bool = false
|
||||||
|
|
||||||
|
|
@ -270,6 +273,8 @@ func _enter_tree() -> void:
|
||||||
_is_2d = false
|
_is_2d = false
|
||||||
camera_3d = parent
|
camera_3d = parent
|
||||||
|
|
||||||
|
if not is_node_ready(): return
|
||||||
|
|
||||||
if _is_2d:
|
if _is_2d:
|
||||||
if not _phantom_camera_manager.get_phantom_camera_2ds().is_empty():
|
if not _phantom_camera_manager.get_phantom_camera_2ds().is_empty():
|
||||||
for pcam in _phantom_camera_manager.get_phantom_camera_2ds():
|
for pcam in _phantom_camera_manager.get_phantom_camera_2ds():
|
||||||
|
|
@ -373,11 +378,10 @@ func _find_pcam_with_highest_priority() -> void:
|
||||||
func _check_pcam_priority(pcam: Node) -> void:
|
func _check_pcam_priority(pcam: Node) -> void:
|
||||||
if not _pcam_is_in_host_layer(pcam): return
|
if not _pcam_is_in_host_layer(pcam): return
|
||||||
if not pcam.visible: return # Prevents hidden PCams from becoming active
|
if not pcam.visible: return # Prevents hidden PCams from becoming active
|
||||||
if pcam.get_priority() > _active_pcam_priority:
|
if pcam.get_priority() >= _active_pcam_priority:
|
||||||
_assign_new_active_pcam(pcam)
|
_assign_new_active_pcam(pcam)
|
||||||
_active_pcam_missing = false
|
_active_pcam_missing = false
|
||||||
else:
|
pcam.set_tween_skip(self, false)
|
||||||
pcam.set_tween_skip(self, false)
|
|
||||||
|
|
||||||
|
|
||||||
func _assign_new_active_pcam(pcam: Node) -> void:
|
func _assign_new_active_pcam(pcam: Node) -> void:
|
||||||
|
|
|
||||||
|
|
@ -21,97 +21,96 @@ public class Camera3DResource(Resource resource)
|
||||||
|
|
||||||
public KeepAspect KeepAspect
|
public KeepAspect KeepAspect
|
||||||
{
|
{
|
||||||
get => (KeepAspect)(int)Resource.Call(MethodName.GetKeepAspect);
|
get => (KeepAspect)(int)Resource.Get(PropertyName.KeepAspect);
|
||||||
set => Resource.Call(MethodName.SetKeepAspect, (int)value);
|
set => Resource.Set(PropertyName.KeepAspect, (int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int CullMask
|
public int CullMask
|
||||||
{
|
{
|
||||||
get => (int)Resource.Call(MethodName.GetCullMask);
|
get => (int)Resource.Get(PropertyName.CullMask);
|
||||||
set => Resource.Call(MethodName.SetCullMask, value);
|
set => Resource.Set(PropertyName.CullMask, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCullMaskValue(int layer, bool value) => Resource.Call(MethodName.SetCullMaskValue, layer, value);
|
|
||||||
|
|
||||||
public float HOffset
|
public float HOffset
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetHOffset);
|
get => (float)Resource.Get(PropertyName.HOffset);
|
||||||
set => Resource.Call(MethodName.SetHOffset, value);
|
set => Resource.Set(PropertyName.HOffset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float VOffset
|
public float VOffset
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetVOffset);
|
get => (float)Resource.Get(PropertyName.VOffset);
|
||||||
set => Resource.Call(MethodName.SetVOffset, value);
|
set => Resource.Set(PropertyName.VOffset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProjectionType Projection
|
public ProjectionType Projection
|
||||||
{
|
{
|
||||||
get => (ProjectionType)(int)Resource.Call(MethodName.GetProjection);
|
get => (ProjectionType)(int)Resource.Get(PropertyName.Projection);
|
||||||
set => Resource.Call(MethodName.SetProjection, (int)value);
|
set => Resource.Set(PropertyName.Projection, (int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Fov
|
public float Fov
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetFov);
|
get => (float)Resource.Get(PropertyName.Fov);
|
||||||
set => Resource.Call(MethodName.SetFov, Mathf.Clamp(value, 1, 179));
|
set => Resource.Set(PropertyName.Fov, Mathf.Clamp(value, 1, 179));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Size
|
public float Size
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetSize);
|
get => (float)Resource.Get(PropertyName.Size);
|
||||||
set => Resource.Call(MethodName.SetSize, Mathf.Clamp(value, 0.001f, float.PositiveInfinity));
|
set => Resource.Set(PropertyName.Size, Mathf.Clamp(value, 0.001f, float.PositiveInfinity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public Vector2 FrustumOffset
|
public Vector2 FrustumOffset
|
||||||
{
|
{
|
||||||
get => (Vector2)Resource.Call(MethodName.GetFrustumOffset);
|
get => (Vector2)Resource.Get(PropertyName.FrustumOffset);
|
||||||
set => Resource.Call(MethodName.SetFrustumOffset, value);
|
set => Resource.Set(PropertyName.FrustumOffset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Near
|
public float Near
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetNear);
|
get => (float)Resource.Get(PropertyName.Near);
|
||||||
set => Resource.Call(MethodName.SetNear, Mathf.Clamp(value, 0.001f, float.PositiveInfinity));
|
set => Resource.Set(PropertyName.Near, Mathf.Clamp(value, 0.001f, float.PositiveInfinity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public float Far
|
public float Far
|
||||||
{
|
{
|
||||||
get => (float)Resource.Call(MethodName.GetFar);
|
get => (float)Resource.Get(PropertyName.Far);
|
||||||
set => Resource.Call(MethodName.SetFar, Mathf.Clamp(value, 0.01f, float.PositiveInfinity));
|
set => Resource.Set(PropertyName.Far, Mathf.Clamp(value, 0.01f, float.PositiveInfinity));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class MethodName
|
public static Camera3DResource New()
|
||||||
{
|
{
|
||||||
public const string GetKeepAspect = "get_keep_aspect";
|
Resource resource = new();
|
||||||
public const string SetKeepAspect = "set_keep_aspect";
|
#if GODOT4_4_OR_GREATER
|
||||||
|
resource.SetScript(GD.Load<GDScript>("uid://b8hhnqsugykly"));
|
||||||
|
#else
|
||||||
|
resource.SetScript(GD.Load<GDScript>("res://addons/phantom_camera/scripts/resources/camera_3d_resource.gd"));
|
||||||
|
#endif
|
||||||
|
return new Camera3DResource(resource);
|
||||||
|
}
|
||||||
|
|
||||||
public const string GetCullMask = "get_cull_mask";
|
public static class PropertyName
|
||||||
public const string SetCullMask = "set_cull_mask";
|
{
|
||||||
public const string SetCullMaskValue = "set_cull_mask_value";
|
public static readonly StringName KeepAspect = new("keep_aspect");
|
||||||
|
|
||||||
public const string GetHOffset = "get_h_offset";
|
public static readonly StringName CullMask = new("cull_mask");
|
||||||
public const string SetHOffset = "set_h_offset";
|
|
||||||
|
|
||||||
public const string GetVOffset = "get_v_offset";
|
public static readonly StringName HOffset = new("h_offset");
|
||||||
public const string SetVOffset = "set_v_offset";
|
|
||||||
|
|
||||||
public const string GetProjection = "get_projection";
|
public static readonly StringName VOffset = new("v_offset");
|
||||||
public const string SetProjection = "set_projection";
|
|
||||||
|
|
||||||
public const string GetFov = "get_fov";
|
public static readonly StringName Projection = new("projection");
|
||||||
public const string SetFov = "set_fov";
|
|
||||||
|
|
||||||
public const string GetSize = "get_size";
|
public static readonly StringName Fov = new("fov");
|
||||||
public const string SetSize = "set_size";
|
|
||||||
|
|
||||||
public const string GetFrustumOffset = "get_frustum_offset";
|
public static readonly StringName Size = new("size");
|
||||||
public const string SetFrustumOffset = "set_frustum_offset";
|
|
||||||
|
|
||||||
public const string GetNear = "get_near";
|
public static readonly StringName FrustumOffset = new("frustum_offset");
|
||||||
public const string SetNear = "set_near";
|
|
||||||
|
|
||||||
public const string GetFar = "get_far";
|
public static readonly StringName Near = new("near");
|
||||||
public const string SetFar = "set_far";
|
|
||||||
|
public static readonly StringName Far = new("far");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -60,33 +60,44 @@ public class PhantomCameraNoise2D(Resource resource)
|
||||||
set => Resource.Call(MethodName.SetPositionalMultiplierY, value);
|
set => Resource.Call(MethodName.SetPositionalMultiplierY, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PhantomCameraNoise2D New()
|
||||||
|
{
|
||||||
|
Resource resource = new();
|
||||||
|
#if GODOT4_4_OR_GREATER
|
||||||
|
resource.SetScript(GD.Load<GDScript>("uid://dimvdouy8g0sv"));
|
||||||
|
#else
|
||||||
|
resource.SetScript(GD.Load<GDScript>("res://addons/phantom_camera/scripts/resources/phantom_camera_noise_2d.gd"));
|
||||||
|
#endif
|
||||||
|
return new PhantomCameraNoise2D(resource);
|
||||||
|
}
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetAmplitude = "get_amplitude";
|
public static readonly StringName GetAmplitude = new("get_amplitude");
|
||||||
public const string SetAmplitude = "set_amplitude";
|
public static readonly StringName SetAmplitude = new("set_amplitude");
|
||||||
|
|
||||||
public const string GetFrequency = "get_frequency";
|
public static readonly StringName GetFrequency = new("get_frequency");
|
||||||
public const string SetFrequency = "set_frequency";
|
public static readonly StringName SetFrequency = new("set_frequency");
|
||||||
|
|
||||||
public const string GetRandomizeNoiseSeed = "get_randomize_noise_seed";
|
public static readonly StringName GetRandomizeNoiseSeed = new("get_randomize_noise_seed");
|
||||||
public const string SetRandomizeNoiseSeed = "set_randomize_noise_seed";
|
public static readonly StringName SetRandomizeNoiseSeed = new("set_randomize_noise_seed");
|
||||||
|
|
||||||
public const string GetNoiseSeed = "get_noise_seed";
|
public static readonly StringName GetNoiseSeed = new("get_noise_seed");
|
||||||
public const string SetNoiseSeed = "set_noise_seed";
|
public static readonly StringName SetNoiseSeed = new("set_noise_seed");
|
||||||
|
|
||||||
public const string GetRotationalNoise = "get_rotational_noise";
|
public static readonly StringName GetRotationalNoise = new("get_rotational_noise");
|
||||||
public const string SetRotationalNoise = "set_rotational_noise";
|
public static readonly StringName SetRotationalNoise = new("set_rotational_noise");
|
||||||
|
|
||||||
public const string GetPositionalNoise = "get_positional_noise";
|
public static readonly StringName GetPositionalNoise = new("get_positional_noise");
|
||||||
public const string SetPositionalNoise = "set_positional_noise";
|
public static readonly StringName SetPositionalNoise = new("set_positional_noise");
|
||||||
|
|
||||||
public const string GetRotationalMultiplier = "get_rotational_multiplier";
|
public static readonly StringName GetRotationalMultiplier = new("get_rotational_multiplier");
|
||||||
public const string SetRotationalMultiplier = "set_rotational_multiplier";
|
public static readonly StringName SetRotationalMultiplier = new("set_rotational_multiplier");
|
||||||
|
|
||||||
public const string GetPositionalMultiplierX = "get_positional_multiplier_x";
|
public static readonly StringName GetPositionalMultiplierX = new("get_positional_multiplier_x");
|
||||||
public const string SetPositionalMultiplierX = "set_positional_multiplier_x";
|
public static readonly StringName SetPositionalMultiplierX = new("set_positional_multiplier_x");
|
||||||
|
|
||||||
public const string GetPositionalMultiplierY = "get_positional_multiplier_y";
|
public static readonly StringName GetPositionalMultiplierY = new("get_positional_multiplier_y");
|
||||||
public const string SetPositionalMultiplierY = "set_positional_multiplier_y";
|
public static readonly StringName SetPositionalMultiplierY = new("set_positional_multiplier_y");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -78,42 +78,53 @@ public class PhantomCameraNoise3D(Resource resource)
|
||||||
set => Resource.Call(MethodName.SetPositionalMultiplierZ, value);
|
set => Resource.Call(MethodName.SetPositionalMultiplierZ, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PhantomCameraNoise3D New()
|
||||||
|
{
|
||||||
|
Resource resource = new();
|
||||||
|
#if GODOT4_4_OR_GREATER
|
||||||
|
resource.SetScript(GD.Load<GDScript>("uid://cuffvge5ad4aa"));
|
||||||
|
#else
|
||||||
|
resource.SetScript(GD.Load<GDScript>("res://addons/phantom_camera/scripts/resources/phantom_camera_noise_3d.gd"));
|
||||||
|
#endif
|
||||||
|
return new PhantomCameraNoise3D(resource);
|
||||||
|
}
|
||||||
|
|
||||||
public static class MethodName
|
public static class MethodName
|
||||||
{
|
{
|
||||||
public const string GetAmplitude = "get_amplitude";
|
public static readonly StringName GetAmplitude = new("get_amplitude");
|
||||||
public const string SetAmplitude = "set_amplitude";
|
public static readonly StringName SetAmplitude = new("set_amplitude");
|
||||||
|
|
||||||
public const string GetFrequency = "get_frequency";
|
public static readonly StringName GetFrequency = new("get_frequency");
|
||||||
public const string SetFrequency = "set_frequency";
|
public static readonly StringName SetFrequency = new("set_frequency");
|
||||||
|
|
||||||
public const string GetRandomizeNoiseSeed = "get_randomize_noise_seed";
|
public static readonly StringName GetRandomizeNoiseSeed = new("get_randomize_noise_seed");
|
||||||
public const string SetRandomizeNoiseSeed = "set_randomize_noise_seed";
|
public static readonly StringName SetRandomizeNoiseSeed = new("set_randomize_noise_seed");
|
||||||
|
|
||||||
public const string GetNoiseSeed = "get_noise_seed";
|
public static readonly StringName GetNoiseSeed = new("get_noise_seed");
|
||||||
public const string SetNoiseSeed = "set_noise_seed";
|
public static readonly StringName SetNoiseSeed = new("set_noise_seed");
|
||||||
|
|
||||||
public const string GetRotationalNoise = "get_rotational_noise";
|
public static readonly StringName GetRotationalNoise = new("get_rotational_noise");
|
||||||
public const string SetRotationalNoise = "set_rotational_noise";
|
public static readonly StringName SetRotationalNoise = new("set_rotational_noise");
|
||||||
|
|
||||||
public const string GetPositionalNoise = "get_positional_noise";
|
public static readonly StringName GetPositionalNoise = new("get_positional_noise");
|
||||||
public const string SetPositionalNoise = "set_positional_noise";
|
public static readonly StringName SetPositionalNoise = new("set_positional_noise");
|
||||||
|
|
||||||
public const string GetRotationalMultiplierX = "get_rotational_multiplier_x";
|
public static readonly StringName GetRotationalMultiplierX = new("get_rotational_multiplier_x");
|
||||||
public const string SetRotationalMultiplierX = "set_rotational_multiplier_x";
|
public static readonly StringName SetRotationalMultiplierX = new("set_rotational_multiplier_x");
|
||||||
|
|
||||||
public const string GetRotationalMultiplierY = "get_rotational_multiplier_y";
|
public static readonly StringName GetRotationalMultiplierY = new("get_rotational_multiplier_y");
|
||||||
public const string SetRotationalMultiplierY = "set_rotational_multiplier_y";
|
public static readonly StringName SetRotationalMultiplierY = new("set_rotational_multiplier_y");
|
||||||
|
|
||||||
public const string GetRotationalMultiplierZ = "get_rotational_multiplier_z";
|
public static readonly StringName GetRotationalMultiplierZ = new("get_rotational_multiplier_z");
|
||||||
public const string SetRotationalMultiplierZ = "set_rotational_multiplier_z";
|
public static readonly StringName SetRotationalMultiplierZ = new("set_rotational_multiplier_z");
|
||||||
|
|
||||||
public const string GetPositionalMultiplierX = "get_positional_multiplier_x";
|
public static readonly StringName GetPositionalMultiplierX = new("get_positional_multiplier_x");
|
||||||
public const string SetPositionalMultiplierX = "set_positional_multiplier_x";
|
public static readonly StringName SetPositionalMultiplierX = new("set_positional_multiplier_x");
|
||||||
|
|
||||||
public const string GetPositionalMultiplierY = "get_positional_multiplier_y";
|
public static readonly StringName GetPositionalMultiplierY = new("get_positional_multiplier_y");
|
||||||
public const string SetPositionalMultiplierY = "set_positional_multiplier_y";
|
public static readonly StringName SetPositionalMultiplierY = new("set_positional_multiplier_y");
|
||||||
|
|
||||||
public const string GetPositionalMultiplierZ = "get_positional_multiplier_z";
|
public static readonly StringName GetPositionalMultiplierZ = new("get_positional_multiplier_z");
|
||||||
public const string SetPositionalMultiplierZ = "set_positional_multiplier_z";
|
public static readonly StringName SetPositionalMultiplierZ = new("set_positional_multiplier_z");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,10 +55,21 @@ public class PhantomCameraTween(Resource tweenResource)
|
||||||
set => Resource.Set(PropertyName.Ease, (int)value);
|
set => Resource.Set(PropertyName.Ease, (int)value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static PhantomCameraTween New()
|
||||||
|
{
|
||||||
|
Resource resource = new();
|
||||||
|
#if GODOT4_4_OR_GREATER
|
||||||
|
resource.SetScript(GD.Load<GDScript>("uid://8umksf8e80fw"));
|
||||||
|
#else
|
||||||
|
resource.SetScript(GD.Load<GDScript>("res://addons/phantom_camera/scripts/resources/tween_resource.gd"));
|
||||||
|
#endif
|
||||||
|
return new PhantomCameraTween(resource);
|
||||||
|
}
|
||||||
|
|
||||||
public static class PropertyName
|
public static class PropertyName
|
||||||
{
|
{
|
||||||
public const string Duration = "duration";
|
public static readonly StringName Duration = new("duration");
|
||||||
public const string Transition = "transition";
|
public static readonly StringName Transition = new("transition");
|
||||||
public const string Ease = "ease";
|
public static readonly StringName Ease = new("ease");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ func _ready() -> void:
|
||||||
component_owner = owner
|
component_owner = owner
|
||||||
|
|
||||||
#组件在初始化时都会等待character的加载
|
#组件在初始化时都会等待character的加载
|
||||||
if not component_owner.is_node_ready() : await component_owner.ready
|
if component_owner and not component_owner.is_node_ready() : await component_owner.ready
|
||||||
_init_component()
|
_init_component()
|
||||||
|
|
||||||
@abstract
|
@abstract
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
[gd_scene format=3 uid="uid://dfm5wy1rmci68"]
|
||||||
|
|
||||||
|
[node name="Anchor" type="Node2D"]
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
[gd_scene load_steps=3 format=3 uid="uid://ddwoxlqluxiq5"]
|
||||||
|
|
||||||
|
[ext_resource type="Script" uid="uid://bvxgviq7l64ck" path="res://addons/reedcomponent/grap_hook/garpping_hook_v_2.gd" id="1_jrg4x"]
|
||||||
|
|
||||||
|
[sub_resource type="CircleShape2D" id="CircleShape2D_jrg4x"]
|
||||||
|
|
||||||
|
[node name="GarppingHookV2" type="Node2D"]
|
||||||
|
script = ExtResource("1_jrg4x")
|
||||||
|
|
||||||
|
[node name="Line2D" type="Line2D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
points = PackedVector2Array(0, 0, 80, 0)
|
||||||
|
width = 8.0
|
||||||
|
|
||||||
|
[node name="Area2D" type="Area2D" parent="."]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
position = Vector2(80, 0)
|
||||||
|
collision_layer = 0
|
||||||
|
collision_mask = 4
|
||||||
|
|
||||||
|
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
|
||||||
|
shape = SubResource("CircleShape2D_jrg4x")
|
||||||
|
debug_color = Color(0, 0.6399631, 0.3615963, 0.41960785)
|
||||||
|
|
@ -0,0 +1,144 @@
|
||||||
|
class_name Hook extends Node2D
|
||||||
|
|
||||||
|
## ================
|
||||||
|
## Export Field
|
||||||
|
## ================
|
||||||
|
@export var min_length := 140
|
||||||
|
@export var max_length := 200
|
||||||
|
@export var streching_speed:float = 1400
|
||||||
|
|
||||||
|
## 线段
|
||||||
|
@onready var line_2d: Line2D = %Line2D
|
||||||
|
## 检测碰撞的区域
|
||||||
|
@onready var area_2d: Area2D = %Area2D
|
||||||
|
|
||||||
|
|
||||||
|
const GRAPABLE_GROUP = &"GRAPABLE"
|
||||||
|
const ANCHOR_NODE = preload("uid://dfm5wy1rmci68")
|
||||||
|
|
||||||
|
signal stretching_finished(reach_limit:bool, anchor_node: Node2D)
|
||||||
|
|
||||||
|
## ================
|
||||||
|
## Private Field
|
||||||
|
## ================
|
||||||
|
var _binded_hook_comp
|
||||||
|
var _is_stretching: bool = false
|
||||||
|
var _stretching_dir: Vector2 = Vector2.ZERO
|
||||||
|
var _cached_cancel: bool = false
|
||||||
|
var _anchor: Node2D
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
area_2d.position = Vector2.ZERO
|
||||||
|
|
||||||
|
area_2d.area_entered.connect(grap_detected)
|
||||||
|
area_2d.body_entered.connect(grap_detected)
|
||||||
|
|
||||||
|
##初始化
|
||||||
|
func init(hook_comp:SpawnHookComponet,reset_to_target: bool):
|
||||||
|
|
||||||
|
_binded_hook_comp = hook_comp
|
||||||
|
if reset_to_target:
|
||||||
|
var p : Vector2= hook_comp.owner.global_position
|
||||||
|
self.global_position = p
|
||||||
|
|
||||||
|
##开始stretching
|
||||||
|
func start_stretching(direction: Vector2) -> void:
|
||||||
|
_is_stretching = true
|
||||||
|
_cached_cancel = false
|
||||||
|
_stretching_dir = direction
|
||||||
|
|
||||||
|
##结束stretching
|
||||||
|
func end_stretching(force_end: bool = false) -> bool:
|
||||||
|
|
||||||
|
##如果还没有达到最短的stretching length,则继续
|
||||||
|
if not force_end and _is_stretching:
|
||||||
|
var d = self.global_position.distance_to(area_2d.global_position)
|
||||||
|
if d < min_length:
|
||||||
|
_cached_cancel = true
|
||||||
|
return false
|
||||||
|
|
||||||
|
_is_stretching = false
|
||||||
|
_stretching_dir = Vector2.ZERO
|
||||||
|
return true
|
||||||
|
|
||||||
|
##是否正在stretching
|
||||||
|
func is_stretching() -> bool:
|
||||||
|
return _is_stretching
|
||||||
|
|
||||||
|
##物理更新
|
||||||
|
func _physics_process(delta: float) -> void:
|
||||||
|
if _is_stretching:
|
||||||
|
_update_stretching(delta)
|
||||||
|
|
||||||
|
##更新绳索的动画表现
|
||||||
|
func _process(delta: float) -> void:
|
||||||
|
update_line_target_pos_with_index(0,self.global_position)
|
||||||
|
update_line_target_pos_with_index(1,area_2d.global_position)
|
||||||
|
|
||||||
|
##更新钩爪爪手的位置
|
||||||
|
func _update_stretching(delta: float) -> void:
|
||||||
|
var d = self.global_position.distance_to(area_2d.global_position)
|
||||||
|
|
||||||
|
#如果已经存在一个缓存的取消,且当前的长度小于最小长度,则直接取消
|
||||||
|
if _cached_cancel:
|
||||||
|
if d >= min_length:
|
||||||
|
stretching_finished.emit(true,null)
|
||||||
|
end_stretching(true)
|
||||||
|
return
|
||||||
|
|
||||||
|
#如果达到的最大的长度,直接取消
|
||||||
|
if d > max_length:
|
||||||
|
stretching_finished.emit(true,null)
|
||||||
|
end_stretching(true)
|
||||||
|
return
|
||||||
|
|
||||||
|
area_2d.global_position += delta * streching_speed * _stretching_dir
|
||||||
|
|
||||||
|
## ================
|
||||||
|
## Tool Func
|
||||||
|
## ================
|
||||||
|
|
||||||
|
##更新特定点的位置
|
||||||
|
func update_line_target_pos_with_index(point_index: int, target_pos: Vector2) -> void:
|
||||||
|
line_2d.set_point_position(
|
||||||
|
point_index,
|
||||||
|
target_pos - global_position
|
||||||
|
)
|
||||||
|
|
||||||
|
##当触碰到可以被抓握的Area后,自动在当前位置生成一个钩爪锚点,后续的移动交给其他系统
|
||||||
|
func grap_detected(node: Node2D) -> void:
|
||||||
|
if node.is_in_group(GRAPABLE_GROUP):
|
||||||
|
end_stretching(true)
|
||||||
|
var d : float= self.global_position.distance_to(area_2d.global_position)
|
||||||
|
var b = d == max_length
|
||||||
|
|
||||||
|
var anchor := _create_anchor_on_node(node)
|
||||||
|
if anchor:
|
||||||
|
stretching_finished.emit(b,anchor)
|
||||||
|
|
||||||
|
##创建钩爪锚点
|
||||||
|
func _create_anchor_on_node(area: Node2D) -> Node2D:
|
||||||
|
# 如果之前有锚点,先清掉
|
||||||
|
if _anchor and is_instance_valid(_anchor):
|
||||||
|
_anchor.queue_free()
|
||||||
|
|
||||||
|
# 1. 创建 Anchor
|
||||||
|
_anchor = Node2D.new()
|
||||||
|
_anchor.name = "Anchor"
|
||||||
|
add_child(_anchor)
|
||||||
|
|
||||||
|
# 2. Anchor 初始位置 = Area 当前世界位置
|
||||||
|
_anchor.global_position = area.global_position
|
||||||
|
|
||||||
|
# 3. 在 Area 上挂 RemoteTransform2D
|
||||||
|
var remote := RemoteTransform2D.new()
|
||||||
|
remote.name = "AnchorRemote"
|
||||||
|
area.add_child(remote)
|
||||||
|
|
||||||
|
remote.remote_path = _anchor.get_path()
|
||||||
|
|
||||||
|
# 4. 只同步位置(锚点一般不需要跟旋转/缩放)
|
||||||
|
remote.update_rotation = false
|
||||||
|
remote.update_scale = false
|
||||||
|
|
||||||
|
return _anchor
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://bvxgviq7l64ck
|
||||||
|
|
@ -6,96 +6,89 @@ class_name SpawnHookComponet extends ComponentBase
|
||||||
@export var binded_hook_move_input_property_name: StringName
|
@export var binded_hook_move_input_property_name: StringName
|
||||||
|
|
||||||
##用於Grapping Hook的基本Instance
|
##用於Grapping Hook的基本Instance
|
||||||
const GRAPPING_HOOK = preload("uid://wlbuqjf2rg03")
|
const GRAPPING_HOOK = preload("uid://ddwoxlqluxiq5")
|
||||||
|
|
||||||
var _ray_direction: Vector2
|
var _ray_direction: Vector2
|
||||||
var _ray_reference: RayCast2D
|
var _ray_reference: RayCast2D
|
||||||
var _ray_length: float = 100
|
var _ray_length: float = 100
|
||||||
|
|
||||||
##當前的Graphook的實例
|
##當前的Graphook的實例
|
||||||
var _current_grap_hook_inst: GrappingHook
|
var _current_grap_hook_inst: Hook
|
||||||
|
|
||||||
##钩爪伸长达到动画位置
|
##钩爪伸长达到动画位置
|
||||||
signal hook_reach_finished
|
signal hook_reach_finished(reach_limit: float, anchor: Node2D)
|
||||||
|
|
||||||
func _physics_process(delta: float) -> void:
|
|
||||||
|
|
||||||
#更新當前的grap_hook的移動
|
|
||||||
update_grap_physics(get_grap_move_input(),delta)
|
|
||||||
|
|
||||||
##用来设置绑定的Ray的方向。
|
|
||||||
func set_ray_direction(in_direction: Vector2) -> Vector2:
|
|
||||||
|
|
||||||
if _ray_direction == in_direction:
|
|
||||||
return _ray_direction
|
|
||||||
|
|
||||||
_ray_direction = in_direction
|
|
||||||
|
|
||||||
if _ray_reference:
|
|
||||||
_ray_reference.target_position = Vector2(
|
|
||||||
_ray_direction.x,
|
|
||||||
_ray_direction.y
|
|
||||||
) * _ray_length
|
|
||||||
|
|
||||||
return _ray_direction
|
|
||||||
|
|
||||||
##生成一个Grap Hook
|
##生成一个Grap Hook
|
||||||
func spawn_grap_hook_inst() -> GrappingHook:
|
func spawn_grap_hook_inst(dir: Vector2) -> Hook:
|
||||||
##如果沒有正確的和任何可以抓取的物體發生碰撞,會直接返回
|
|
||||||
if not _ray_reference.is_colliding(): return null
|
|
||||||
|
|
||||||
var i = GRAPPING_HOOK.instantiate() as GrappingHook
|
var i = GRAPPING_HOOK.instantiate() as Hook
|
||||||
i.init(self)
|
i.init(self,true)
|
||||||
get_tree().current_scene.add_child(i)
|
get_tree().current_scene.add_child(i)
|
||||||
i.start_hook_with_instigator(_ray_reference.get_collision_point(),component_owner)
|
i.start_stretching(dir)
|
||||||
_current_grap_hook_inst = i
|
_current_grap_hook_inst = i
|
||||||
|
|
||||||
|
i.stretching_finished.connect(_on_hook_stretching_end)
|
||||||
return _current_grap_hook_inst
|
return _current_grap_hook_inst
|
||||||
|
|
||||||
func grap_reach_target(duration: float) -> bool:
|
##尝试关闭hook的延长
|
||||||
if not _ray_reference or not _current_grap_hook_inst:return false
|
func suspend_hook_stretching(force_suspend: bool = false) -> bool:
|
||||||
|
if not _current_grap_hook_inst: return false
|
||||||
|
return _current_grap_hook_inst.end_stretching(force_suspend)
|
||||||
|
|
||||||
##重置所有Points的坐标点位置。
|
##当Hook stretching 关闭的时候,触发。
|
||||||
_current_grap_hook_inst.reset_line_points_to_target(component_owner.global_position)
|
func _on_hook_stretching_end(reach_limit,anchor:Node2D) -> void:
|
||||||
|
hook_reach_finished.emit(reach_limit,anchor)
|
||||||
|
|
||||||
var start_pos: Vector2 = component_owner.global_position
|
##从当前的hook获取到hook的anchor
|
||||||
var target_pos: Vector2 = _ray_reference.get_collision_point()
|
func get_current_hook_anchor() -> Node2D:
|
||||||
|
return _current_grap_hook_inst._anchor
|
||||||
|
|
||||||
var t := get_tree().create_tween()
|
#func grap_reach_target(duration: float) -> bool:
|
||||||
t.set_trans(Tween.TRANS_SINE)
|
#if not _ray_reference or not _current_grap_hook_inst:return false
|
||||||
t.set_ease(Tween.EASE_OUT)
|
#
|
||||||
|
###重置所有Points的坐标点位置。
|
||||||
t.tween_method(
|
#_current_grap_hook_inst.reset_line_points_to_target(component_owner.global_position)
|
||||||
_current_grap_hook_inst.update_line_anchor_pos,
|
#
|
||||||
start_pos,
|
#var start_pos: Vector2 = component_owner.global_position
|
||||||
target_pos,
|
#var target_pos: Vector2 = _ray_reference.get_collision_point()
|
||||||
duration
|
#
|
||||||
)
|
#var t := get_tree().create_tween()
|
||||||
|
#t.set_trans(Tween.TRANS_SINE)
|
||||||
##结束时会发送广播
|
#t.set_ease(Tween.EASE_OUT)
|
||||||
t.finished.connect(_on_hook_reach_finished)
|
#
|
||||||
|
#t.tween_method(
|
||||||
return true
|
#_current_grap_hook_inst.update_line_anchor_pos,
|
||||||
|
#start_pos,
|
||||||
##更新GrapHook的物理
|
#target_pos,
|
||||||
func update_grap_physics(input: Vector2,delta: float) -> void:
|
#duration
|
||||||
if input.is_zero_approx(): return
|
#)
|
||||||
if not _current_grap_hook_inst: return
|
#
|
||||||
|
###结束时会发送广播
|
||||||
var i = input.normalized()
|
#t.finished.connect(_on_hook_reach_finished)
|
||||||
_current_grap_hook_inst.move_hook(input,delta)
|
#
|
||||||
|
#return true
|
||||||
##此函數默認為Vector.Zeor,子類可以重寫以得到一個全新的結果,也可以通過綁定的方式獲得一個結果。
|
#
|
||||||
func get_grap_move_input() -> Vector2:
|
###更新GrapHook的物理
|
||||||
|
#func update_grap_physics(input: Vector2,delta: float) -> void:
|
||||||
#如果我們在組件裏綁定了Component上的一個字段,也可以直接獲取。
|
#if input.is_zero_approx(): return
|
||||||
if binded_hook_move_input_property_name in component_owner:
|
#if not _current_grap_hook_inst: return
|
||||||
return component_owner.get(binded_hook_move_input_property_name)
|
#
|
||||||
|
#var i = input.normalized()
|
||||||
return Vector2.ZERO
|
#_current_grap_hook_inst.move_hook(input,delta)
|
||||||
|
#
|
||||||
func _on_hook_reach_finished() -> void:
|
###此函數默認為Vector.Zeor,子類可以重寫以得到一個全新的結果,也可以通過綁定的方式獲得一個結果。
|
||||||
_current_grap_hook_inst.m_update_rope_with_nodes = true
|
#func get_grap_move_input() -> Vector2:
|
||||||
hook_reach_finished.emit()
|
#
|
||||||
|
##如果我們在組件裏綁定了Component上的一個字段,也可以直接獲取。
|
||||||
|
#if binded_hook_move_input_property_name in component_owner:
|
||||||
|
#return component_owner.get(binded_hook_move_input_property_name)
|
||||||
|
#
|
||||||
|
#return Vector2.ZERO
|
||||||
|
#
|
||||||
|
#func _on_hook_reach_finished() -> void:
|
||||||
|
#_current_grap_hook_inst.m_update_rope_with_nodes = true
|
||||||
|
#hook_reach_finished.emit()
|
||||||
|
#
|
||||||
|
|
||||||
func _init_component() -> void:
|
func _init_component() -> void:
|
||||||
_ray_reference = binded_hook_ray_cast_2d
|
pass
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
@icon("res://addons/reedscene/act/icon/ActIcon.svg")
|
||||||
|
class_name Act
|
||||||
|
extends Resource
|
||||||
|
|
||||||
|
##prop_state_map,通过输入Dictionary和状态来设定State
|
||||||
|
@export var prop_state_map: Dictionary[int, SingleAct] = {}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://fxpk2ot6otfh
|
||||||
|
|
@ -0,0 +1,117 @@
|
||||||
|
#@icon("")
|
||||||
|
@tool
|
||||||
|
class_name ActManager extends Node
|
||||||
|
|
||||||
|
##ActManager里记录了一系列的ActID和对应的Act,主要用来同步场景的Act,比如,我们现在使用ActID = 0的Act,那么就会让所有的Act的状态重置回到ActID = 0的Act的状态
|
||||||
|
@export var prop_state_map: Dictionary[int, Act] = {}
|
||||||
|
|
||||||
|
##用于生成一个基础的Act的工具按钮
|
||||||
|
@export_tool_button("Generate Default Act")
|
||||||
|
var _gen_default_act: Callable = Callable(self, "_editor_generate_default_act")
|
||||||
|
|
||||||
|
##是否要输出报错信息
|
||||||
|
@export var debug_log: bool = false
|
||||||
|
|
||||||
|
##用来扫描prop
|
||||||
|
func _scan_scene_for_props(scene_root: Node) -> Dictionary:
|
||||||
|
var result := {}
|
||||||
|
|
||||||
|
if scene_root == null:
|
||||||
|
return result
|
||||||
|
|
||||||
|
_scan_node_recursive(scene_root, result)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
##递归扫描
|
||||||
|
func _scan_node_recursive(node: Node, out: Dictionary) -> void:
|
||||||
|
if node is PropComponent:
|
||||||
|
var prop := node as PropComponent
|
||||||
|
if out.has(prop.prop_id):
|
||||||
|
push_warning(
|
||||||
|
"[ActManagerInspector] Duplicate prop_id: %d (%s)"
|
||||||
|
% [prop.prop_id, node.get_path()]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
out[prop.prop_id] = {
|
||||||
|
"node": prop,
|
||||||
|
"path": node.get_path()
|
||||||
|
}
|
||||||
|
|
||||||
|
for child in node.get_children():
|
||||||
|
_scan_node_recursive(child, out)
|
||||||
|
|
||||||
|
func _editor_generate_default_act() -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
var scene := _get_owner_scene()
|
||||||
|
if scene == null:
|
||||||
|
_editor_popup(
|
||||||
|
"ActManager must be a child of ReedScene.",
|
||||||
|
"Generate Default Act - Failed"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
var props_root := scene.get_node_or_null(scene.props_root_path)
|
||||||
|
if props_root == null:
|
||||||
|
_editor_popup(
|
||||||
|
"Props root not found:\n%s" % scene.props_root_path,
|
||||||
|
"Generate Default Act - Failed"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
var act := Act.new()
|
||||||
|
act.prop_state_map.clear()
|
||||||
|
|
||||||
|
var count := 0
|
||||||
|
|
||||||
|
for prop_node in props_root.get_children():
|
||||||
|
if not prop_node is Node:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var prop_comp := _find_prop_component_top(prop_node)
|
||||||
|
if prop_comp == null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var pid := prop_comp.prop_id
|
||||||
|
var init_state := prop_comp.initial_state_id
|
||||||
|
act.prop_state_map[pid] = init_state
|
||||||
|
count += 1
|
||||||
|
|
||||||
|
prop_state_map[0] = act
|
||||||
|
|
||||||
|
notify_property_list_changed()
|
||||||
|
|
||||||
|
_editor_popup(
|
||||||
|
"Default Act generated successfully.\n\nProp count: %d\nAct ID: 0" % count,
|
||||||
|
"Generate Default Act - Success"
|
||||||
|
)
|
||||||
|
|
||||||
|
if debug_log:
|
||||||
|
print("[ActManager][Editor] Generated Default Act with", count, "props.")
|
||||||
|
|
||||||
|
## ==============================
|
||||||
|
## 工具函数
|
||||||
|
## ==============================
|
||||||
|
func _editor_popup(message: String, title: String = "ActManager") -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
var dialog := AcceptDialog.new()
|
||||||
|
dialog.title = title
|
||||||
|
dialog.dialog_text = message
|
||||||
|
get_tree().root.add_child(dialog)
|
||||||
|
dialog.popup_centered()
|
||||||
|
|
||||||
|
func _get_owner_scene() -> ReedScene:
|
||||||
|
var p := get_parent()
|
||||||
|
if p is ReedScene:
|
||||||
|
return p as ReedScene
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _find_prop_component_top(prop: Node) -> PropComponent:
|
||||||
|
for child in prop.get_children():
|
||||||
|
if child is PropComponent:
|
||||||
|
return child as PropComponent
|
||||||
|
return null
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
@tool
|
||||||
|
extends EditorInspectorPlugin
|
||||||
|
|
||||||
|
# ✅ 由 EditorPlugin 注入
|
||||||
|
var editor_interface: EditorInterface
|
||||||
|
|
||||||
|
func _can_handle(object) -> bool:
|
||||||
|
return object is ActManager
|
||||||
|
|
||||||
|
func _parse_begin(object) -> void:
|
||||||
|
var act_manager := object as ActManager
|
||||||
|
var reed_scene := _get_owner_scene(act_manager)
|
||||||
|
|
||||||
|
var text := ""
|
||||||
|
text += "Act Table (Debug)\n"
|
||||||
|
text += "Act Count: %d\n" % act_manager.prop_state_map.size()
|
||||||
|
text += "------------------\n"
|
||||||
|
|
||||||
|
if reed_scene == null:
|
||||||
|
text += "ERROR: ActManager must be a direct child of ReedScene.\n"
|
||||||
|
text += "Current parent: %s\n" % (act_manager.get_parent().name if act_manager.get_parent() else "<null>")
|
||||||
|
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = text
|
||||||
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||||
|
add_custom_control(label)
|
||||||
|
return
|
||||||
|
|
||||||
|
var props_root := reed_scene.get_node_or_null(reed_scene.props_root_path)
|
||||||
|
if props_root == null:
|
||||||
|
text += "ERROR: ReedScene Props root not found: %s\n" % str(reed_scene.props_root_path)
|
||||||
|
|
||||||
|
var label2 := Label.new()
|
||||||
|
label2.text = text
|
||||||
|
label2.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||||
|
add_custom_control(label2)
|
||||||
|
return
|
||||||
|
|
||||||
|
# ✅ 只扫描 Props root 下的 Prop
|
||||||
|
var prop_index := _scan_props_root_for_props(props_root)
|
||||||
|
|
||||||
|
text += "Scene: %s\n" % reed_scene.name
|
||||||
|
text += "Props Root: %s\n" % str(props_root.get_path())
|
||||||
|
text += "Prop Count: %d\n" % prop_index.size()
|
||||||
|
text += "------------------\n"
|
||||||
|
|
||||||
|
for prop_id in prop_index.keys():
|
||||||
|
var info: Dictionary = prop_index[prop_id]
|
||||||
|
text += "PropID: %d | %s\n" % [int(prop_id), str(info["path"])]
|
||||||
|
|
||||||
|
var label := Label.new()
|
||||||
|
label.text = text
|
||||||
|
label.autowrap_mode = TextServer.AUTOWRAP_WORD
|
||||||
|
add_custom_control(label)
|
||||||
|
|
||||||
|
##扫描Prop root
|
||||||
|
func _scan_props_root_for_props(props_root: Node) -> Dictionary:
|
||||||
|
var result := {}
|
||||||
|
|
||||||
|
for prop in props_root.get_children():
|
||||||
|
if not prop is Node:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# PropComponent 必须在 prop 的最上层子节点集中
|
||||||
|
var prop_comp := _find_prop_component_in_top_children(prop)
|
||||||
|
if prop_comp == null:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var pid := prop_comp.prop_id
|
||||||
|
if result.has(pid):
|
||||||
|
var old_info: Dictionary = result[pid]
|
||||||
|
push_warning(
|
||||||
|
"[ActManagerInspector] Duplicate prop_id under Props root: %d\n A: %s\n B: %s"
|
||||||
|
% [pid, str(old_info["path"]), str(prop_comp.get_path())]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
result[pid] = {
|
||||||
|
"node": prop_comp,
|
||||||
|
"path": prop_comp.get_path()
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
##获取到Prop下的所有的PropComponent
|
||||||
|
func _find_prop_component_in_top_children(prop: Node) -> PropComponent:
|
||||||
|
for child in prop.get_children():
|
||||||
|
if child is PropComponent:
|
||||||
|
return child as PropComponent
|
||||||
|
return null
|
||||||
|
|
||||||
|
##获取到ActManager上方的Scene,应当自查为ReedScene
|
||||||
|
func _get_owner_scene(act_manager: ActManager) -> ReedScene:
|
||||||
|
var p := act_manager.get_parent()
|
||||||
|
if p is ReedScene:
|
||||||
|
return p as ReedScene
|
||||||
|
return null
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://082tx8ee707t
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
class_name SingleAct extends Resource
|
||||||
|
|
||||||
|
@export var state_id: int = 0
|
||||||
|
@export var use_trans: bool = false
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://baqgorvlumyju
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
class_name ActManager extends Node
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767102882495" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="17013" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M513.194667 85.290667c-17.664 0-35.541333 9.856-41.344 30.677333l-14.634667 54.656H299.861333a128 128 0 0 0-128 128v298.666667a128 128 0 0 0 128 128h2.688L258.56 883.968c-6.314667 22.698667 6.613333 47.018667 29.312 53.333333 22.698667 6.314667 47.018667-6.656 53.333333-29.354666l50.688-182.656h78.634667v128a42.666667 42.666667 0 0 0 85.333333 0v-128h78.677334l50.688 182.656c6.272 22.698667 30.592 35.669333 53.333333 29.354666 22.698667-6.314667 35.626667-30.634667 29.312-53.333333l-43.989333-158.677333h2.645333a128 128 0 0 0 128-128v-298.666667a128 128 0 0 0-128-128h-157.312l-14.677333-54.656c-5.802667-20.821333-23.68-30.677333-41.344-30.677333z" fill="#be8dbd" p-id="17014"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.0 KiB |
|
|
@ -0,0 +1,43 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://dkkvlam0m6cno"
|
||||||
|
path="res://.godot/imported/ActIcon.svg-bc2f37aa408ca4bb121c48c1713e51e9.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/reedscene/act/icon/ActIcon.svg"
|
||||||
|
dest_files=["res://.godot/imported/ActIcon.svg-bc2f37aa408ca4bb121c48c1713e51e9.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
[plugin]
|
[plugin]
|
||||||
|
|
||||||
name="ReedScene"
|
name="ReedScene"
|
||||||
description=""
|
description="这是一个用于2D游戏场景管理的插件,通过组件化的方式,将一个场景分成了场景中的各个组件和组件所对应的状态,用户可以通过切换状态,来实现一些动画的效果,也可以通过切换状态,来快速的事件存档,不同事件触发不同的结果的任务系统等,总之比较灵活"
|
||||||
author="ReedZhu"
|
author="ReedZhu"
|
||||||
version=""
|
version=".1"
|
||||||
script="reedscene.gd"
|
script="reedscene.gd"
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ class_name PropComponent extends Node
|
||||||
## Export
|
## Export
|
||||||
## ==============================
|
## ==============================
|
||||||
|
|
||||||
##此物件的描述ID
|
##此物件的描述ID,无法主动修改,由PropManager发信
|
||||||
@export var prop_id: int
|
@export_custom(PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY) var prop_id: int = -1
|
||||||
|
|
||||||
##初始的默认state_id
|
##初始的默认state_id
|
||||||
@export var initial_state_id: int = 0
|
@export var initial_state_id: int = 0
|
||||||
|
|
@ -61,11 +61,16 @@ func _build_state_cache() -> void:
|
||||||
push_warning("[PropComponent:%s] States root not found" % prop_id)
|
push_warning("[PropComponent:%s] States root not found" % prop_id)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if not _states_root is ReedPropStateManager:
|
||||||
|
push_error("[PropComponent:%s] States root is not ReedPropStateManager" % prop_id)
|
||||||
|
return
|
||||||
|
|
||||||
for c in _states_root.get_children():
|
for c in _states_root.get_children():
|
||||||
if c is ReedPropState:
|
if c is ReedPropState:
|
||||||
var s := c as ReedPropState
|
var s := c as ReedPropState
|
||||||
if _state_map.has(s.state_id):
|
if _state_map.has(s.state_id):
|
||||||
push_error("[PropComponent:%s] Duplicate state_id: %d" % [prop_id, s.state_id])
|
push_error("[PropComponent:%s] Duplicate state_id: %d"
|
||||||
|
% [prop_id, s.state_id])
|
||||||
continue
|
continue
|
||||||
_state_map[s.state_id] = s
|
_state_map[s.state_id] = s
|
||||||
|
|
||||||
|
|
@ -167,12 +172,19 @@ func _editor_ensure_states_root() -> void:
|
||||||
if states != null:
|
if states != null:
|
||||||
return
|
return
|
||||||
|
|
||||||
states = Node.new()
|
# 创建 StateManager 而不是普通 Node
|
||||||
|
states = ReedPropStateManager.new()
|
||||||
states.name = states_root_name
|
states.name = states_root_name
|
||||||
add_child(states)
|
add_child(states)
|
||||||
|
|
||||||
# ⚠️ 关键:让它成为 Scene 的一部分
|
# 让其成为 Scene 的一部分(非常重要)
|
||||||
states.owner = get_tree().edited_scene_root
|
states.owner = get_tree().edited_scene_root
|
||||||
|
|
||||||
|
# 自动添加一个默认 State
|
||||||
|
var default_state := ReedPropState.new()
|
||||||
|
default_state.name = "Default"
|
||||||
|
states.add_child(default_state)
|
||||||
|
default_state.owner = get_tree().edited_scene_root
|
||||||
|
|
||||||
if debug_log:
|
if debug_log:
|
||||||
print("[PropComponent] Created States root")
|
print("[PropComponent] Created States(StateManager) + Default State")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
@tool
|
||||||
|
class_name PropManager
|
||||||
|
extends Node2D
|
||||||
|
|
||||||
|
##是否要自动的向其子集中添加一个PropComp
|
||||||
|
@export var auto_attach_prop_component := true
|
||||||
|
|
||||||
|
##是否要输出Debug Message
|
||||||
|
@export var debug_log := true
|
||||||
|
|
||||||
|
##输出一个ID的前缀,方便策划调整
|
||||||
|
const PREFIX := "[Prop_%04d]"
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
_ensure_existing_props()
|
||||||
|
child_entered_tree.connect(_on_child_entered_tree)
|
||||||
|
|
||||||
|
# 强制让 Editor 重新计算 configuration warnings
|
||||||
|
update_configuration_warnings()
|
||||||
|
|
||||||
|
func _on_child_entered_tree(node: Node) -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
_try_attach_and_assign(node)
|
||||||
|
|
||||||
|
# 子节点变化后,刷新 Inspector 警告
|
||||||
|
update_configuration_warnings()
|
||||||
|
|
||||||
|
func _ensure_existing_props() -> void:
|
||||||
|
for child in get_children():
|
||||||
|
_try_attach_and_assign(child)
|
||||||
|
|
||||||
|
func _try_attach_and_assign(prop: Node) -> void:
|
||||||
|
if not auto_attach_prop_component:
|
||||||
|
return
|
||||||
|
if prop == null:
|
||||||
|
return
|
||||||
|
if prop is PropComponent:
|
||||||
|
return
|
||||||
|
|
||||||
|
var comp := _find_prop_component_top(prop)
|
||||||
|
if comp == null:
|
||||||
|
comp = PropComponent.new()
|
||||||
|
comp.name = "PropComponent" # 临时名
|
||||||
|
prop.add_child(comp)
|
||||||
|
comp.owner = get_tree().edited_scene_root
|
||||||
|
|
||||||
|
# 确保 prop_id 唯一且有效
|
||||||
|
if int(comp.prop_id) < 0 or _is_prop_id_used_elsewhere(int(comp.prop_id), comp):
|
||||||
|
comp.prop_id = _alloc_prop_id()
|
||||||
|
|
||||||
|
# 用 prop_id 重命名 PropComponent
|
||||||
|
comp.name = PREFIX % int(comp.prop_id)
|
||||||
|
|
||||||
|
if debug_log:
|
||||||
|
print("[PropManager][Editor] Ensure PropComponent:", prop.name, "->", comp.name, "id=", comp.prop_id)
|
||||||
|
|
||||||
|
func _find_prop_component_top(prop: Node) -> PropComponent:
|
||||||
|
for child in prop.get_children():
|
||||||
|
if child is PropComponent:
|
||||||
|
return child as PropComponent
|
||||||
|
return null
|
||||||
|
|
||||||
|
func _alloc_prop_id() -> int:
|
||||||
|
var max_id := -1
|
||||||
|
|
||||||
|
for prop in get_children():
|
||||||
|
var comp := _find_prop_component_top(prop)
|
||||||
|
if comp == null:
|
||||||
|
continue
|
||||||
|
max_id = maxi(max_id, int(comp.prop_id))
|
||||||
|
|
||||||
|
return max_id + 1
|
||||||
|
|
||||||
|
func _is_prop_id_used_elsewhere(prop_id: int, self_comp: PropComponent) -> bool:
|
||||||
|
for prop in get_children():
|
||||||
|
var comp := _find_prop_component_top(prop)
|
||||||
|
if comp == null:
|
||||||
|
continue
|
||||||
|
if comp == self_comp:
|
||||||
|
continue
|
||||||
|
if int(comp.prop_id) == prop_id:
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
||||||
|
# =====================================================
|
||||||
|
# Editor Configuration Warnings(Inspector 黄色警告)
|
||||||
|
# =====================================================
|
||||||
|
func _get_configuration_warnings() -> PackedStringArray:
|
||||||
|
var warnings := PackedStringArray()
|
||||||
|
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return warnings
|
||||||
|
|
||||||
|
for prop in get_children():
|
||||||
|
if prop is PropComponent:
|
||||||
|
continue
|
||||||
|
|
||||||
|
var comp := _find_prop_component_top(prop)
|
||||||
|
if comp == null:
|
||||||
|
warnings.append(
|
||||||
|
"Prop '%s' has no PropComponent as a top-level child." % prop.name
|
||||||
|
)
|
||||||
|
|
||||||
|
return warnings
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://pxjf5vst08eo
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
@icon("res://addons/reedscene/prop/icon/prop_state_icon.svg")
|
@icon("res://addons/reedscene/prop/icon/prop_state_icon.svg")
|
||||||
class_name ReedPropState extends Node
|
class_name ReedPropState extends Node
|
||||||
|
|
||||||
##状态编号,默认为-1,-1是不可用编号,请修改
|
##状态编号,默认为-1,-1是不可用编号,状态编号由StateManager发布,不可以自己修改。
|
||||||
@export var state_id: int = -1
|
@export_custom(PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY) var state_id: int = -1
|
||||||
##该State的信息是否需要被存入Save中
|
##该State的信息是否需要被存入Save中
|
||||||
@export var save_game: bool = false
|
@export var save_game: bool = false
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
@tool
|
||||||
|
@icon("res://addons/reedscene/prop/icon/prop_states_manager.svg")
|
||||||
|
class_name ReedPropStateManager
|
||||||
|
extends Node
|
||||||
|
|
||||||
|
@export var auto_refresh: bool = true
|
||||||
|
|
||||||
|
func _ready() -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
child_entered_tree.connect(_on_child_entered_tree)
|
||||||
|
child_exiting_tree.connect(_on_child_exiting_tree)
|
||||||
|
|
||||||
|
_refresh_states()
|
||||||
|
|
||||||
|
func _notification(what: int) -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
if what == NOTIFICATION_CHILD_ORDER_CHANGED:
|
||||||
|
if auto_refresh:
|
||||||
|
call_deferred("_refresh_states")
|
||||||
|
|
||||||
|
func _on_child_entered_tree(node: Node) -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
if node is ReedPropState and auto_refresh:
|
||||||
|
call_deferred("_refresh_states")
|
||||||
|
|
||||||
|
func _on_child_exiting_tree(node: Node) -> void:
|
||||||
|
if not Engine.is_editor_hint():
|
||||||
|
return
|
||||||
|
|
||||||
|
if node is ReedPropState and auto_refresh:
|
||||||
|
call_deferred("_refresh_states")
|
||||||
|
|
||||||
|
func _refresh_states() -> void:
|
||||||
|
var index := 0
|
||||||
|
|
||||||
|
for child in get_children():
|
||||||
|
if not child is ReedPropState:
|
||||||
|
continue
|
||||||
|
|
||||||
|
_assign_state_id(child, index)
|
||||||
|
_rename_state_node(child, index)
|
||||||
|
index += 1
|
||||||
|
|
||||||
|
func _assign_state_id(state: ReedPropState, id: int) -> void:
|
||||||
|
if state.state_id == id:
|
||||||
|
return
|
||||||
|
|
||||||
|
state.set("state_id", id)
|
||||||
|
|
||||||
|
func _rename_state_node(state: ReedPropState, id: int) -> void:
|
||||||
|
var base_name := _strip_id_prefix(state.name)
|
||||||
|
var expected := "[ID_%d] %s" % [id, base_name]
|
||||||
|
|
||||||
|
if state.name == expected:
|
||||||
|
return
|
||||||
|
|
||||||
|
state.name = expected
|
||||||
|
|
||||||
|
func _strip_id_prefix(name: String) -> String:
|
||||||
|
var result := name
|
||||||
|
|
||||||
|
# 连续剥离所有 [ID_x] 前缀,防止叠加
|
||||||
|
while result.begins_with("[ID_"):
|
||||||
|
var end := result.find("]")
|
||||||
|
if end == -1:
|
||||||
|
break
|
||||||
|
|
||||||
|
# 跳过 "] " 或 "]"
|
||||||
|
var cut := end + 1
|
||||||
|
if cut < result.length() and result[cut] == " ":
|
||||||
|
cut += 1
|
||||||
|
|
||||||
|
result = result.substr(cut)
|
||||||
|
|
||||||
|
return result.strip_edges()
|
||||||
|
|
||||||
|
func _extract_raw_name(name: String) -> String:
|
||||||
|
if name.begins_with("[ID:"):
|
||||||
|
var end := name.find("]")
|
||||||
|
if end != -1 and end + 2 < name.length():
|
||||||
|
return name.substr(end + 2)
|
||||||
|
return name
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
uid://di41kt2tj34c2
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1767100309546" class="icon" viewBox="0 0 1026 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6972" xmlns:xlink="http://www.w3.org/1999/xlink" width="200.390625" height="200"><path d="M1005.065 566.407L778.527 438.471a38.248 38.248 0 0 0 3.614-15.299V170.734a38.55 38.55 0 0 0-20.359-34.092L533.317 5.695a38.067 38.067 0 0 0-40.055 0L264.736 136.642a38.971 38.971 0 0 0-20.419 34.092c0.06 1.686 0.542 3.192 0.723 4.819v247.619a38.67 38.67 0 0 0 3.855 15.6L21.514 566.407a39.754 39.754 0 0 0-20.359 34.092V856.31c1.084 13.07 9.035 24.636 21.082 30.72l227.02 130.947a42.404 42.404 0 0 0 20.418 5.42 42.585 42.585 0 0 0 20.42-5.42L515.97 891.185l220.574 126.792a38.067 38.067 0 0 0 20.36 5.42 41.44 41.44 0 0 0 17.527-5.42l230.634-128.237a38.61 38.61 0 0 0 20.419-34.092V600.499a40.236 40.236 0 0 0-20.42-34.092zM704.139 399.982l-151.126 83.182V319.21l151.126-82.76v163.533z m52.041 282.374l-143.536-79.99-3.313-1.867 147.572-82.52 146.97 81.195-147.693 83.182zM513.62 84.781l146.91 83.242-148.295 82.58-146.246-82.58L513.62 84.781zM270.399 517.979l146.85 82.52-6.265 3.494-142.03 78.363L122.706 600.5l147.692-82.52zM309.731 915.7V751.444l147.692-82.64v163.654L309.73 915.7z m634.137-83.242L796.236 915.7V750.781l93.903-52.282 53.729-29.755v163.714z" p-id="6973" fill="#d4237a"></path></svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,43 @@
|
||||||
|
[remap]
|
||||||
|
|
||||||
|
importer="texture"
|
||||||
|
type="CompressedTexture2D"
|
||||||
|
uid="uid://ebci83e8e4c5"
|
||||||
|
path="res://.godot/imported/prop_states_manager.svg-00bb8dafdf44685d5ebeae84cfe13a05.ctex"
|
||||||
|
metadata={
|
||||||
|
"vram_texture": false
|
||||||
|
}
|
||||||
|
|
||||||
|
[deps]
|
||||||
|
|
||||||
|
source_file="res://addons/reedscene/prop/icon/prop_states_manager.svg"
|
||||||
|
dest_files=["res://.godot/imported/prop_states_manager.svg-00bb8dafdf44685d5ebeae84cfe13a05.ctex"]
|
||||||
|
|
||||||
|
[params]
|
||||||
|
|
||||||
|
compress/mode=0
|
||||||
|
compress/high_quality=false
|
||||||
|
compress/lossy_quality=0.7
|
||||||
|
compress/uastc_level=0
|
||||||
|
compress/rdo_quality_loss=0.0
|
||||||
|
compress/hdr_compression=1
|
||||||
|
compress/normal_map=0
|
||||||
|
compress/channel_pack=0
|
||||||
|
mipmaps/generate=false
|
||||||
|
mipmaps/limit=-1
|
||||||
|
roughness/mode=0
|
||||||
|
roughness/src_normal=""
|
||||||
|
process/channel_remap/red=0
|
||||||
|
process/channel_remap/green=1
|
||||||
|
process/channel_remap/blue=2
|
||||||
|
process/channel_remap/alpha=3
|
||||||
|
process/fix_alpha_border=true
|
||||||
|
process/premult_alpha=false
|
||||||
|
process/normal_map_invert_y=false
|
||||||
|
process/hdr_as_srgb=false
|
||||||
|
process/hdr_clamp_exposure=false
|
||||||
|
process/size_limit=0
|
||||||
|
detect_3d/compress_to=1
|
||||||
|
svg/scale=1.0
|
||||||
|
editor/scale_with_editor_scale=false
|
||||||
|
editor/convert_colors_with_editor_theme=false
|
||||||
|
|
@ -1,2 +1,14 @@
|
||||||
@tool
|
@tool
|
||||||
extends EditorPlugin
|
extends EditorPlugin
|
||||||
|
|
||||||
|
var inspector_plugin
|
||||||
|
|
||||||
|
func _enter_tree() -> void:
|
||||||
|
inspector_plugin = preload("res://addons/reedscene/act/ActManagerInspector.gd").new()
|
||||||
|
# ✅ 注入 EditorInterface
|
||||||
|
inspector_plugin.editor_interface = get_editor_interface()
|
||||||
|
add_inspector_plugin(inspector_plugin)
|
||||||
|
|
||||||
|
func _exit_tree() -> void:
|
||||||
|
if inspector_plugin:
|
||||||
|
remove_inspector_plugin(inspector_plugin)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
@tool
|
@tool
|
||||||
@icon("uid://p0oxphym6oqg")
|
@icon("uid://p0oxphym6oqg")
|
||||||
|
|
||||||
'''
|
'''
|
||||||
此类为一个level的最小单元,其可以承载任意多的prop和act
|
此类为一个level的最小单元,其可以承载任意多的prop和act
|
||||||
你可以这样理解,一个level(大关卡),带有n个小关卡,n = scene的数量
|
你可以这样理解,一个level(大关卡),带有n个小关卡,n = scene的数量
|
||||||
|
|
@ -24,10 +23,29 @@
|
||||||
|
|
||||||
对于Scene,Scene通过PropComponent上的ID,通过ID获取到PropComponent所挂载的组件,这也是为什么我强制要求
|
对于Scene,Scene通过PropComponent上的ID,通过ID获取到PropComponent所挂载的组件,这也是为什么我强制要求
|
||||||
PropComponent必须是处于Prop的最上层子节点集。
|
PropComponent必须是处于Prop的最上层子节点集。
|
||||||
|
|
||||||
|
Scene自身也有SceneID,SceneID是实现跨Scene修改的核心,SceneID是插件内置的系统主动生成的,且理论上不允许修改,
|
||||||
|
对于每个Scene来说,SceneID是唯一且绝对的,这个涉及到后续的异步加载问题,虽然2D游戏可能没有这些问题。
|
||||||
|
|
||||||
|
比如说,我们可以让玩家在Scene1的时候,触发Scene9的一个ActChange,发射一个火焰流星雨,但是实际上这个东西是可以被在Scene的玩家所
|
||||||
|
观察的。
|
||||||
'''
|
'''
|
||||||
|
|
||||||
class_name ReedScene extends Node2D
|
class_name ReedScene extends Node2D
|
||||||
|
|
||||||
|
## ==============================
|
||||||
|
## Const Config
|
||||||
|
## ==============================
|
||||||
|
|
||||||
|
##Act管理器的命名
|
||||||
|
const ACT_MANAGER_NAME := "ActManager"
|
||||||
|
|
||||||
|
##Prop的根节点命名
|
||||||
|
const PROPS_ROOT_NAME := "Props"
|
||||||
|
|
||||||
|
##场景管理器的根节点命名
|
||||||
|
const SCENE_MANAGER_NAME := "SceneManager"
|
||||||
|
|
||||||
## ==============================
|
## ==============================
|
||||||
## Export Config
|
## Export Config
|
||||||
## ==============================
|
## ==============================
|
||||||
|
|
@ -44,11 +62,11 @@ var _props_root: Node
|
||||||
var _prop_map: Dictionary = {} # prop_id -> PropComponent
|
var _prop_map: Dictionary = {} # prop_id -> PropComponent
|
||||||
|
|
||||||
## ==============================
|
## ==============================
|
||||||
## Lifecycle
|
##
|
||||||
## ==============================
|
## ==============================
|
||||||
func _enter_tree() -> void:
|
func _enter_tree() -> void:
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
_editor_auto_attach_prop_components()
|
_editor_ensure_scene_nodes() ##进入场景树,自动添加ActManager,PropsRoot,和SceneManager
|
||||||
|
|
||||||
## ==============================
|
## ==============================
|
||||||
## Resolve References
|
## Resolve References
|
||||||
|
|
@ -119,30 +137,29 @@ func _on_act_changed(from_act: StringName, to_act: StringName) -> void:
|
||||||
for prop_comp in _prop_map.values():
|
for prop_comp in _prop_map.values():
|
||||||
prop_comp.on_act_changed(from_act, to_act)
|
prop_comp.on_act_changed(from_act, to_act)
|
||||||
|
|
||||||
## ==============================
|
##进入场景树,自动添加ActManager,PropsRoot,和SceneManager
|
||||||
## Editor Helpers
|
func _editor_ensure_scene_nodes() -> void:
|
||||||
## ==============================
|
_editor_ensure_node(SCENE_MANAGER_NAME, SceneManager)
|
||||||
func _editor_auto_attach_prop_components() -> void:
|
_editor_ensure_node(ACT_MANAGER_NAME, ActManager)
|
||||||
if not auto_attach_prop_component:
|
_editor_ensure_node(PROPS_ROOT_NAME, PropManager)
|
||||||
return
|
|
||||||
|
|
||||||
var props_root := get_node_or_null(props_root_path)
|
##添加命名和节点
|
||||||
if props_root == null:
|
func _editor_ensure_node(name: String, type: Variant) -> Node:
|
||||||
return
|
var node := get_node_or_null(name)
|
||||||
|
if node != null:
|
||||||
|
return node
|
||||||
|
|
||||||
for prop in props_root.get_children():
|
node = type.new()
|
||||||
if not prop is Node:
|
node.name = name
|
||||||
continue
|
add_child(node)
|
||||||
|
|
||||||
if _find_prop_component(prop) != null:
|
# ⚠️ 关键:让节点成为 Scene 的一部分
|
||||||
continue
|
node.owner = get_tree().edited_scene_root
|
||||||
|
|
||||||
var comp := PropComponent.new()
|
if debug_log:
|
||||||
prop.add_child(comp)
|
print("[ReedScene][Editor] Created node:", name)
|
||||||
comp.owner = get_tree().edited_scene_root
|
|
||||||
|
|
||||||
if debug_log:
|
return node
|
||||||
print("[ReedScene][Editor] Auto attached PropComponent to:", prop.name)
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
_resolve_act_manager()
|
_resolve_act_manager()
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
# ReedScene 插件更新列表
|
||||||
|
|
||||||
|
## 更新日志
|
||||||
|
|
||||||
|
V0.1
|
||||||
|
|
||||||
|
- 添加了基础的Act,Prop,Scene的概念。
|
||||||
|
|
||||||
|
## 更新计划
|
||||||
|
|
||||||
|
V0.1
|
||||||
|
|
||||||
|
主要的工作是搭建一个插件的基本架构
|
||||||
|
|
||||||
|
- [x] 角色墙滑
|
||||||
|
|
@ -39,6 +39,7 @@ enabled=PackedStringArray("res://addons/phantom_camera/plugin.cfg", "res://addon
|
||||||
|
|
||||||
ROOM="房间分组,其下存在所有的Room"
|
ROOM="房间分组,其下存在所有的Room"
|
||||||
PLAYER="玩家分组,其下只存在玩家控制器"
|
PLAYER="玩家分组,其下只存在玩家控制器"
|
||||||
|
GRAPABLE=""
|
||||||
|
|
||||||
[input]
|
[input]
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue