Add phantom camera
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
extends Node2D
|
||||
|
||||
@onready var pcam_room_left: PhantomCamera2D = %RoomLeftPhantomCamera2D
|
||||
@onready var pcam_room_centre: PhantomCamera2D = %RoomCentrePhantomCamera2D
|
||||
@onready var pcam_room_right: PhantomCamera2D = %RoomRightPhantomCamera2D
|
||||
|
||||
@onready var player: Node2D = %CharacterBody2D/%PlayerVisuals
|
||||
|
||||
@onready var area_2d_room_left: Area2D = %RoomLeftArea2D
|
||||
@onready var area_2d_room_centre: Area2D = %RoomCentreArea2D
|
||||
@onready var area_2d_room_right: Area2D = %RoomRightArea2D
|
||||
|
||||
|
||||
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_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_left.body_exited.connect(_on_body_exited.bind(pcam_room_left))
|
||||
area_2d_room_centre.body_exited.connect(_on_body_exited.bind(pcam_room_centre))
|
||||
area_2d_room_right.body_exited.connect(_on_body_exited.bind(pcam_room_right))
|
||||
|
||||
|
||||
func _on_body_entered(body: Node2D, pcam: PhantomCamera2D) -> void:
|
||||
if body == player.get_parent():
|
||||
pcam.set_follow_target(player)
|
||||
pcam.set_priority(20)
|
||||
|
||||
|
||||
func _on_body_exited(body: Node2D, pcam: PhantomCamera2D) -> void:
|
||||
if body == player.get_parent():
|
||||
pcam.set_priority(0)
|
||||
pcam.set_follow_target(null)
|
@@ -0,0 +1,36 @@
|
||||
extends Node2D
|
||||
|
||||
@onready var pcam_room_left: PhantomCamera2D = %RoomLeftPhantomCamera2D
|
||||
@onready var pcam_room_centre: PhantomCamera2D = %RoomCentrePhantomCamera2D
|
||||
@onready var pcam_room_right: PhantomCamera2D = %RoomRightPhantomCamera2D
|
||||
|
||||
@onready var player: Node2D = %CharacterBody2D
|
||||
|
||||
@onready var area_2d_room_left: Area2D = %RoomLeftArea2D
|
||||
@onready var area_2d_room_centre: Area2D = %RoomCentreArea2D
|
||||
@onready var area_2d_room_right: Area2D = %RoomRightArea2D
|
||||
|
||||
|
||||
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_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_left.body_exited.connect(_on_body_exited.bind(pcam_room_left))
|
||||
area_2d_room_centre.body_exited.connect(_on_body_exited.bind(pcam_room_centre))
|
||||
area_2d_room_right.body_exited.connect(_on_body_exited.bind(pcam_room_right))
|
||||
|
||||
|
||||
func _on_body_entered(body: Node2D, pcam: PhantomCamera2D) -> void:
|
||||
if body == player:
|
||||
pcam.set_follow_target(player)
|
||||
pcam.set_priority(20)
|
||||
|
||||
|
||||
func _on_body_exited(body: Node2D, pcam: PhantomCamera2D) -> void:
|
||||
if body == player:
|
||||
pcam.set_priority(0)
|
||||
pcam.set_follow_target(null)
|
16
addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd
Normal file
16
addons/phantom_camera/examples/scripts/2D/2d_trigger_area.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends Area2D
|
||||
|
||||
@export var area_pcam: PhantomCamera2D
|
||||
|
||||
func _ready() -> void:
|
||||
connect("area_entered", _entered_area)
|
||||
connect("area_exited", _exited_area)
|
||||
|
||||
func _entered_area(area_2d: Area2D) -> void:
|
||||
if area_2d.get_parent() is CharacterBody2D:
|
||||
area_pcam.set_priority(20)
|
||||
|
||||
func _exited_area(area_2d: Area2D) -> void:
|
||||
if area_2d.get_parent() is CharacterBody2D:
|
||||
area_pcam.set_priority(0)
|
||||
|
@@ -0,0 +1,189 @@
|
||||
extends CharacterBody2D
|
||||
|
||||
@onready var _player_area2d = %PlayerArea2D
|
||||
@onready var _player_visuals: Node2D = %PlayerVisuals
|
||||
@onready var _player_sprite: Sprite2D = %PlayerSprite
|
||||
@onready var _interaction_prompt: Panel = %InteractionPrompt
|
||||
@onready var _ui_sign: Control
|
||||
@onready var _dark_overlay: ColorRect = %DarkOverlay
|
||||
|
||||
const KEY_STRINGNAME: StringName = "Key"
|
||||
const ACTION_STRINGNAME: StringName = "Action"
|
||||
const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left"
|
||||
const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right"
|
||||
|
||||
const SPEED = 350.0
|
||||
const JUMP_VELOCITY = -750.0
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity: int = 2400
|
||||
var _is_interactive: bool
|
||||
var _can_open_inventory: bool
|
||||
var _movement_disabled: bool
|
||||
var tween: Tween
|
||||
var _interactive_UI: Control
|
||||
var _active_pcam: PhantomCamera2D
|
||||
|
||||
var _physics_body_trans_last: Transform2D
|
||||
var _physics_body_trans_current: Transform2D
|
||||
|
||||
enum InteractiveType {
|
||||
NONE = 0,
|
||||
ITEM = 1,
|
||||
INVENTORY = 2,
|
||||
}
|
||||
var _interactive_object: InteractiveType = InteractiveType.NONE
|
||||
|
||||
var InputMovementDic: Dictionary = {
|
||||
INPUT_MOVE_LEFT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_A,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_RIGHT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_D,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_player_area2d.body_shape_entered.connect(_show_prompt)
|
||||
_player_area2d.body_shape_exited.connect(_hide_prompt)
|
||||
|
||||
_ui_sign = owner.get_node("%UISign")
|
||||
|
||||
for input in InputMovementDic:
|
||||
var key_val = InputMovementDic[input].get(KEY_STRINGNAME)
|
||||
var action_val = InputMovementDic[input].get(ACTION_STRINGNAME)
|
||||
|
||||
var movement_input = InputEventKey.new()
|
||||
movement_input.physical_keycode = key_val
|
||||
InputMap.add_action(action_val)
|
||||
InputMap.action_add_event(action_val, movement_input)
|
||||
|
||||
_player_visuals.top_level = true
|
||||
|
||||
if Engine.get_version_info().major == 4 and \
|
||||
Engine.get_version_info().minor >= 3:
|
||||
printerr("Please run the other 2D example scenes, in the 2D-4.3 directory, for more up-to-date example setups.")
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _is_interactive:
|
||||
if Input.is_physical_key_pressed(KEY_F):
|
||||
if tween:
|
||||
tween.kill()
|
||||
|
||||
if not _movement_disabled:
|
||||
tween = get_tree().create_tween()
|
||||
|
||||
_movement_disabled = true
|
||||
_active_pcam.set_priority(10)
|
||||
|
||||
_show_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
else:
|
||||
_hide_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
|
||||
if Input.is_physical_key_pressed(KEY_ESCAPE) and _movement_disabled:
|
||||
_hide_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
|
||||
func _show_interactive_node(UI: Control) -> void:
|
||||
UI.modulate.a = 0
|
||||
UI.visible = true
|
||||
tween.tween_property(UI, "modulate", Color.WHITE, 1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CIRC)
|
||||
|
||||
|
||||
func _hide_interactive_node(UI: Control) -> void:
|
||||
_movement_disabled = false
|
||||
_active_pcam.set_priority(0)
|
||||
UI.visible = false
|
||||
|
||||
|
||||
func _interactive_node_logic() -> void:
|
||||
match _interactive_object:
|
||||
2:
|
||||
if _movement_disabled:
|
||||
_dark_overlay.set_visible(true)
|
||||
else:
|
||||
_dark_overlay.set_visible(false)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_physics_body_trans_last = _physics_body_trans_current
|
||||
_physics_body_trans_current = global_transform
|
||||
|
||||
if not is_on_floor():
|
||||
velocity.y += gravity * delta
|
||||
|
||||
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
||||
velocity.y = JUMP_VELOCITY
|
||||
|
||||
if _movement_disabled: return
|
||||
|
||||
var input_dir: = Input.get_axis(
|
||||
INPUT_MOVE_LEFT_STRINGNAME,
|
||||
INPUT_MOVE_RIGHT_STRINGNAME
|
||||
)
|
||||
|
||||
if input_dir:
|
||||
velocity.x = input_dir * SPEED
|
||||
if input_dir > 0:
|
||||
_player_sprite.set_flip_h(false)
|
||||
elif input_dir < 0:
|
||||
_player_sprite.set_flip_h(true)
|
||||
else:
|
||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
|
||||
func _process(delta) -> void:
|
||||
_player_visuals.global_position = _physics_body_trans_last.interpolate_with(
|
||||
_physics_body_trans_current,
|
||||
Engine.get_physics_interpolation_fraction()
|
||||
).origin
|
||||
|
||||
|
||||
func _show_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void:
|
||||
if body is TileMap:
|
||||
var tile_map: TileMap = body
|
||||
|
||||
var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid)
|
||||
var cell_data: TileData = tile_map.get_cell_tile_data(1, tile_coords)
|
||||
|
||||
if cell_data:
|
||||
var cell_data_type: StringName = cell_data.get_custom_data("Type")
|
||||
# var cell_global_pos: Vector2 = tile_map.to_global(tile_map.map_to_local(tile_coords))
|
||||
_is_interactive = true
|
||||
_interaction_prompt.set_visible(true)
|
||||
|
||||
match cell_data_type:
|
||||
"Sign":
|
||||
_interactive_UI = owner.get_node("%UISign")
|
||||
_active_pcam = %ItemFocusPhantomCamera2D
|
||||
_interactive_object = InteractiveType.ITEM
|
||||
"Inventory":
|
||||
_interactive_UI = owner.get_node("%UIInventory")
|
||||
_interactive_object = InteractiveType.INVENTORY
|
||||
_active_pcam = %InventoryPhantomCamera2D
|
||||
|
||||
|
||||
func _hide_prompt(body_rid: RID, body: Node2D, body_shape_index: int, local_shape: int) -> void:
|
||||
if body is TileMap:
|
||||
var tile_map: TileMap = body
|
||||
|
||||
var tile_coords: Vector2i = tile_map.get_coords_for_body_rid(body_rid)
|
||||
var cell_data: TileData = tile_map.get_cell_tile_data(1, tile_coords)
|
||||
|
||||
if cell_data:
|
||||
_interaction_prompt.set_visible(false)
|
||||
_is_interactive = false
|
||||
_interactive_UI = null
|
||||
_interactive_object = InteractiveType.NONE
|
||||
_active_pcam = null
|
@@ -0,0 +1,179 @@
|
||||
extends CharacterBody2D
|
||||
|
||||
@onready var _player_area2d = %PlayerArea2D
|
||||
@onready var _player_visuals: Node2D = %PlayerVisuals
|
||||
@onready var _player_sprite: Sprite2D = %PlayerSprite
|
||||
@onready var _interaction_prompt: Panel = %InteractionPrompt
|
||||
@onready var _ui_sign: Control
|
||||
@onready var _dark_overlay: ColorRect = %DarkOverlay
|
||||
@onready var _noise_emitter: PhantomCameraNoiseEmitter2D
|
||||
|
||||
const KEY_STRINGNAME: StringName = "Key"
|
||||
const ACTION_STRINGNAME: StringName = "Action"
|
||||
const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left"
|
||||
const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right"
|
||||
|
||||
const SPEED = 350.0
|
||||
const JUMP_VELOCITY = -750.0
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity: int = 2400
|
||||
var _is_interactive: bool
|
||||
var _can_open_inventory: bool
|
||||
var _movement_disabled: bool
|
||||
var tween: Tween
|
||||
var _interactive_UI: Control
|
||||
var _active_pcam: PhantomCamera2D
|
||||
|
||||
enum InteractiveType {
|
||||
NONE = 0,
|
||||
ITEM = 1,
|
||||
INVENTORY = 2,
|
||||
}
|
||||
var _interactive_object: InteractiveType = InteractiveType.NONE
|
||||
|
||||
var InputMovementDic: Dictionary = {
|
||||
INPUT_MOVE_LEFT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_A,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_RIGHT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_D,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
_player_area2d.body_shape_entered.connect(_show_prompt)
|
||||
_player_area2d.body_shape_exited.connect(_hide_prompt)
|
||||
|
||||
_ui_sign = owner.get_node("%UISign")
|
||||
|
||||
for input in InputMovementDic:
|
||||
var key_val = InputMovementDic[input].get(KEY_STRINGNAME)
|
||||
var action_val = InputMovementDic[input].get(ACTION_STRINGNAME)
|
||||
|
||||
var movement_input = InputEventKey.new()
|
||||
movement_input.physical_keycode = key_val
|
||||
InputMap.add_action(action_val)
|
||||
InputMap.action_add_event(action_val, movement_input)
|
||||
|
||||
if Engine.get_version_info().major == 4 and \
|
||||
Engine.get_version_info().minor < 3:
|
||||
printerr("This scene is designed to only work properly in Godot 4.3 or later that supports 2D Physics Interpolation.")
|
||||
printerr("Please run the other 2D example scenes in the other directory.")
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _is_interactive:
|
||||
if Input.is_physical_key_pressed(KEY_F):
|
||||
if tween:
|
||||
tween.kill()
|
||||
|
||||
if not _movement_disabled:
|
||||
tween = get_tree().create_tween()
|
||||
|
||||
_movement_disabled = true
|
||||
_active_pcam.set_priority(10)
|
||||
|
||||
_show_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
else:
|
||||
_hide_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
|
||||
if Input.is_physical_key_pressed(KEY_ESCAPE) and _movement_disabled:
|
||||
_hide_interactive_node(_interactive_UI)
|
||||
_interactive_node_logic()
|
||||
|
||||
if Input.is_physical_key_pressed(KEY_Q):
|
||||
if get_node_or_null("%PlayerPhantomCameraNoiseEmitter2D"):
|
||||
%PlayerPhantomCameraNoiseEmitter2D.emit()
|
||||
|
||||
|
||||
func _show_interactive_node(UI: Control) -> void:
|
||||
UI.modulate.a = 0
|
||||
UI.visible = true
|
||||
tween.tween_property(UI, "modulate", Color.WHITE, 1).set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_CIRC)
|
||||
|
||||
|
||||
func _hide_interactive_node(UI: Control) -> void:
|
||||
_movement_disabled = false
|
||||
_active_pcam.set_priority(0)
|
||||
UI.visible = false
|
||||
|
||||
|
||||
func _interactive_node_logic() -> void:
|
||||
match _interactive_object:
|
||||
2:
|
||||
if _movement_disabled:
|
||||
_dark_overlay.set_visible(true)
|
||||
else:
|
||||
_dark_overlay.set_visible(false)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not is_on_floor():
|
||||
velocity.y += gravity * delta
|
||||
|
||||
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
|
||||
velocity.y = JUMP_VELOCITY
|
||||
|
||||
if _movement_disabled: return
|
||||
|
||||
var input_dir: = Input.get_axis(
|
||||
INPUT_MOVE_LEFT_STRINGNAME,
|
||||
INPUT_MOVE_RIGHT_STRINGNAME
|
||||
)
|
||||
|
||||
if input_dir:
|
||||
velocity.x = input_dir * SPEED
|
||||
if input_dir > 0:
|
||||
_player_sprite.set_flip_h(false)
|
||||
elif input_dir < 0:
|
||||
_player_sprite.set_flip_h(true)
|
||||
else:
|
||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
|
||||
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
|
||||
var tile_map := body
|
||||
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)
|
||||
|
||||
if cell_data:
|
||||
var cell_data_type: StringName = cell_data.get_custom_data("Type")
|
||||
# var cell_global_pos: Vector2 = tile_map.to_global(tile_map.map_to_local(tile_coords))
|
||||
_is_interactive = true
|
||||
_interaction_prompt.set_visible(true)
|
||||
|
||||
match cell_data_type:
|
||||
"Sign":
|
||||
_interactive_UI = owner.get_node("%UISign")
|
||||
_active_pcam = %ItemFocusPhantomCamera2D
|
||||
_interactive_object = InteractiveType.ITEM
|
||||
"Inventory":
|
||||
_interactive_UI = owner.get_node("%UIInventory")
|
||||
_interactive_object = InteractiveType.INVENTORY
|
||||
_active_pcam = %InventoryPhantomCamera2D
|
||||
|
||||
|
||||
func _hide_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
|
||||
var tile_map := body
|
||||
|
||||
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)
|
||||
|
||||
if cell_data:
|
||||
_interaction_prompt.set_visible(false)
|
||||
_is_interactive = false
|
||||
_interactive_UI = null
|
||||
_interactive_object = InteractiveType.NONE
|
||||
_active_pcam = null
|
26
addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd
Normal file
26
addons/phantom_camera/examples/scripts/3D/3d_trigger_area.gd
Normal file
@@ -0,0 +1,26 @@
|
||||
extends Area3D
|
||||
|
||||
@export var area_pcam: PhantomCamera3D
|
||||
|
||||
var initial_camera_position: Vector3
|
||||
var initial_camera_rotation: Vector3
|
||||
|
||||
var tween: Tween
|
||||
var tween_duration: float = 0.9
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
connect("area_entered", _entered_area)
|
||||
connect("area_exited", _exited_area)
|
||||
|
||||
|
||||
func _entered_area(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
area_pcam.set_priority(20)
|
||||
|
||||
|
||||
func _exited_area(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
area_pcam.set_priority(0)
|
||||
|
||||
|
71
addons/phantom_camera/examples/scripts/3D/npc.gd
Normal file
71
addons/phantom_camera/examples/scripts/3D/npc.gd
Normal file
@@ -0,0 +1,71 @@
|
||||
extends Node3D
|
||||
|
||||
@onready var npc_pcam: PhantomCamera3D = %NPCPhantomCamera3D
|
||||
@onready var dialogueArea: Area3D = %NPCInteractionArea3D
|
||||
@onready var dialogueLabel3D: Label3D = %NPCDialogueExampleLabel
|
||||
|
||||
@onready var player: CharacterBody3D = %PlayerCharacterBody3D
|
||||
|
||||
@onready var move_to_location: Vector3 = %MoveToLocation.get_global_position()
|
||||
|
||||
var dialogue_label_initial_position: Vector3
|
||||
var dialogue_label_initial_rotation: Vector3
|
||||
|
||||
var tween: Tween
|
||||
var tween_duration: float = 0.9
|
||||
var tween_transition: Tween.TransitionType = Tween.TRANS_QUAD
|
||||
|
||||
var interactable: bool
|
||||
var is_interacting: bool
|
||||
|
||||
func _ready() -> void:
|
||||
dialogueArea.connect("area_entered", _interactable)
|
||||
dialogueArea.connect("area_exited", _not_interactable)
|
||||
|
||||
dialogueLabel3D.set_visible(false)
|
||||
|
||||
dialogue_label_initial_position = dialogueLabel3D.get_global_position()
|
||||
dialogue_label_initial_rotation = dialogueLabel3D.get_global_rotation()
|
||||
|
||||
npc_pcam.tween_completed.connect(_on_tween_started)
|
||||
|
||||
|
||||
|
||||
func _on_tween_started() -> void:
|
||||
player.movement_enabled = false
|
||||
|
||||
|
||||
func _interactable(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
dialogueLabel3D.set_visible(true)
|
||||
interactable = true
|
||||
|
||||
var tween: Tween = get_tree().create_tween().set_trans(tween_transition).set_ease(Tween.EASE_IN_OUT).set_loops()
|
||||
tween.tween_property(dialogueLabel3D, "global_position", dialogue_label_initial_position - Vector3(0, -0.2, 0), tween_duration)
|
||||
tween.tween_property(dialogueLabel3D, "position", dialogue_label_initial_position, tween_duration)
|
||||
|
||||
|
||||
func _not_interactable(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
dialogueLabel3D.set_visible(false)
|
||||
interactable = false
|
||||
|
||||
|
||||
func _input(event) -> void:
|
||||
if not interactable: return
|
||||
|
||||
if event is InputEventKey and event.pressed:
|
||||
if event.keycode == KEY_F:
|
||||
var tween: Tween = get_tree().create_tween() \
|
||||
.set_parallel(true) \
|
||||
.set_trans(Tween.TRANS_QUART) \
|
||||
.set_ease(Tween.EASE_IN_OUT)
|
||||
if not is_interacting:
|
||||
npc_pcam.priority = 20
|
||||
tween.tween_property(player, "global_position", move_to_location, 0.6).set_trans(tween_transition)
|
||||
tween.tween_property(dialogueLabel3D, "rotation", Vector3(deg_to_rad(-20), deg_to_rad(53), 0), 0.6).set_trans(tween_transition)
|
||||
else:
|
||||
npc_pcam.priority = 0
|
||||
tween.tween_property(dialogueLabel3D, "rotation", dialogue_label_initial_rotation, 0.9)
|
||||
player.movement_enabled = true
|
||||
is_interacting = !is_interacting
|
18
addons/phantom_camera/examples/scripts/3D/path_follow.gd
Normal file
18
addons/phantom_camera/examples/scripts/3D/path_follow.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
extends Node
|
||||
|
||||
@export var path_pcam: PhantomCamera3D
|
||||
|
||||
func _ready() -> void:
|
||||
connect("area_entered", _entered_area)
|
||||
connect("area_exited", _exited_area)
|
||||
|
||||
|
||||
func _entered_area(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
path_pcam.set_priority(20)
|
||||
|
||||
|
||||
func _exited_area(area_3D: Area3D) -> void:
|
||||
if area_3D.get_parent() is CharacterBody3D:
|
||||
path_pcam.set_priority(0)
|
||||
|
103
addons/phantom_camera/examples/scripts/3D/player_controller.gd
Normal file
103
addons/phantom_camera/examples/scripts/3D/player_controller.gd
Normal file
@@ -0,0 +1,103 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
@export var SPEED: float = 5.0
|
||||
@export var JUMP_VELOCITY: float = 4.5
|
||||
@export var enable_gravity = true
|
||||
|
||||
@onready var _camera: Camera3D
|
||||
|
||||
@onready var _player_visual: Node3D = %PlayerVisual
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity: float = 9.8
|
||||
|
||||
var movement_enabled: bool = true
|
||||
|
||||
var _physics_body_trans_last: Transform3D
|
||||
var _physics_body_trans_current: Transform3D
|
||||
|
||||
const KEY_STRINGNAME: StringName = "Key"
|
||||
const ACTION_STRINGNAME: StringName = "Action"
|
||||
|
||||
const INPUT_MOVE_UP_STRINGNAME: StringName = "move_up"
|
||||
const INPUT_MOVE_DOWM_STRINGNAME: StringName = "move_down"
|
||||
const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left"
|
||||
const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right"
|
||||
|
||||
var InputMovementDic: Dictionary = {
|
||||
INPUT_MOVE_UP_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_W,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_UP_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_DOWM_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_S,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_DOWM_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_LEFT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_A,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_RIGHT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_D,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for input in InputMovementDic:
|
||||
var key_val = InputMovementDic[input].get(KEY_STRINGNAME)
|
||||
var action_val = InputMovementDic[input].get(ACTION_STRINGNAME)
|
||||
|
||||
_camera = owner.get_node("%MainCamera3D")
|
||||
|
||||
var movement_input = InputEventKey.new()
|
||||
movement_input.physical_keycode = key_val
|
||||
InputMap.add_action(action_val)
|
||||
InputMap.action_add_event(action_val, movement_input)
|
||||
|
||||
_player_visual.top_level = true
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
_physics_body_trans_last = _physics_body_trans_current
|
||||
_physics_body_trans_current = global_transform
|
||||
|
||||
# Add the gravity.
|
||||
if enable_gravity and not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
if not movement_enabled: return
|
||||
|
||||
# Get the input direction and handle the movement/deceleration.
|
||||
# As good practice, you should replace UI actions with custom gameplay actions.
|
||||
var input_dir: Vector2 = Input.get_vector(
|
||||
INPUT_MOVE_LEFT_STRINGNAME,
|
||||
INPUT_MOVE_RIGHT_STRINGNAME,
|
||||
INPUT_MOVE_UP_STRINGNAME,
|
||||
INPUT_MOVE_DOWM_STRINGNAME
|
||||
)
|
||||
|
||||
var cam_dir: Vector3 = -_camera.global_transform.basis.z
|
||||
|
||||
var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
||||
if direction:
|
||||
var move_dir: Vector3 = Vector3.ZERO
|
||||
move_dir.x = direction.x
|
||||
move_dir.z = direction.z
|
||||
|
||||
move_dir = move_dir.rotated(Vector3.UP, _camera.rotation.y).normalized()
|
||||
velocity.x = move_dir.x * SPEED
|
||||
velocity.z = move_dir.z * SPEED
|
||||
else:
|
||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||
|
||||
move_and_slide()
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
_player_visual.global_transform = _physics_body_trans_last.interpolate_with(
|
||||
_physics_body_trans_current,
|
||||
Engine.get_physics_interpolation_fraction()
|
||||
)
|
@@ -0,0 +1,84 @@
|
||||
extends CharacterBody3D
|
||||
|
||||
@export var SPEED: float = 5.0
|
||||
@export var JUMP_VELOCITY: float = 4.5
|
||||
@export var enable_gravity = true
|
||||
|
||||
@onready var _camera: Camera3D
|
||||
|
||||
# Get the gravity from the project settings to be synced with RigidBody nodes.
|
||||
var gravity: float = 9.8
|
||||
|
||||
var movement_enabled: bool = true
|
||||
|
||||
const KEY_STRINGNAME: StringName = "Key"
|
||||
const ACTION_STRINGNAME: StringName = "Action"
|
||||
|
||||
const INPUT_MOVE_UP_STRINGNAME: StringName = "move_up"
|
||||
const INPUT_MOVE_DOWM_STRINGNAME: StringName = "move_down"
|
||||
const INPUT_MOVE_LEFT_STRINGNAME: StringName = "move_left"
|
||||
const INPUT_MOVE_RIGHT_STRINGNAME: StringName = "move_right"
|
||||
|
||||
var InputMovementDic: Dictionary = {
|
||||
INPUT_MOVE_UP_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_W,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_UP_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_DOWM_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_S,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_DOWM_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_LEFT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_A,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_LEFT_STRINGNAME
|
||||
},
|
||||
INPUT_MOVE_RIGHT_STRINGNAME: {
|
||||
KEY_STRINGNAME: KEY_D,
|
||||
ACTION_STRINGNAME: INPUT_MOVE_RIGHT_STRINGNAME
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
for input in InputMovementDic:
|
||||
var key_val = InputMovementDic[input].get(KEY_STRINGNAME)
|
||||
var action_val = InputMovementDic[input].get(ACTION_STRINGNAME)
|
||||
|
||||
_camera = owner.get_node("%MainCamera3D")
|
||||
|
||||
var movement_input = InputEventKey.new()
|
||||
movement_input.physical_keycode = key_val
|
||||
InputMap.add_action(action_val)
|
||||
InputMap.action_add_event(action_val, movement_input)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
# Add the gravity.
|
||||
if enable_gravity and not is_on_floor():
|
||||
velocity.y -= gravity * delta
|
||||
|
||||
if not movement_enabled: return
|
||||
|
||||
# Get the input direction and handle the movement/deceleration.
|
||||
# As good practice, you should replace UI actions with custom gameplay actions.
|
||||
var input_dir: Vector2 = Input.get_vector(
|
||||
INPUT_MOVE_LEFT_STRINGNAME,
|
||||
INPUT_MOVE_RIGHT_STRINGNAME,
|
||||
INPUT_MOVE_UP_STRINGNAME,
|
||||
INPUT_MOVE_DOWM_STRINGNAME
|
||||
)
|
||||
|
||||
var direction: Vector3 = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
|
||||
if direction:
|
||||
var move_dir: Vector3 = Vector3.ZERO
|
||||
move_dir.x = direction.x
|
||||
move_dir.z = direction.z
|
||||
|
||||
move_dir = move_dir.rotated(Vector3.UP, _camera.rotation.y).normalized()
|
||||
velocity.x = move_dir.x * SPEED
|
||||
velocity.z = move_dir.z * SPEED
|
||||
else:
|
||||
velocity.x = move_toward(velocity.x, 0, SPEED)
|
||||
velocity.z = move_toward(velocity.z, 0, SPEED)
|
||||
|
||||
move_and_slide()
|
@@ -0,0 +1,54 @@
|
||||
extends "player_controller.gd"
|
||||
|
||||
@onready var _player_pcam: PhantomCamera3D = %PlayerPhantomCamera3D
|
||||
|
||||
@onready var _player_character: CharacterBody3D = %PlayerCharacterBody3D
|
||||
|
||||
@export var mouse_sensitivity: float = 0.05
|
||||
|
||||
@export var min_pitch: float = -89.9
|
||||
@export var max_pitch: float = 50
|
||||
|
||||
@export var min_yaw: float = 0
|
||||
@export var max_yaw: float = 360
|
||||
|
||||
@export var run_noise: PhantomCameraNoise3D
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"):
|
||||
%EmitterTip.visible = true
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
super(delta)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventKey:
|
||||
if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"):
|
||||
if event.keycode == KEY_Q and event.is_pressed():
|
||||
%PlayerPhantomCameraNoiseEmitter3D.emit()
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
var pcam_rotation_degrees: Vector3
|
||||
|
||||
# Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor
|
||||
pcam_rotation_degrees = _player_pcam.rotation_degrees
|
||||
|
||||
# Change the X rotation
|
||||
pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity
|
||||
|
||||
# Clamp the rotation in the X axis so it go over or under the target
|
||||
pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch)
|
||||
|
||||
# Change the Y rotation value
|
||||
pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity
|
||||
|
||||
# Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively
|
||||
pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw)
|
||||
|
||||
# Change the SpringArm3D node's rotation and rotate around its target
|
||||
_player_pcam.rotation_degrees = pcam_rotation_degrees
|
@@ -0,0 +1,54 @@
|
||||
extends "player_controller_4.4.gd"
|
||||
|
||||
@onready var _player_pcam: PhantomCamera3D = %PlayerPhantomCamera3D
|
||||
|
||||
@onready var _player_character: CharacterBody3D = %PlayerCharacterBody3D
|
||||
|
||||
@export var mouse_sensitivity: float = 0.05
|
||||
|
||||
@export var min_pitch: float = -89.9
|
||||
@export var max_pitch: float = 50
|
||||
|
||||
@export var min_yaw: float = 0
|
||||
@export var max_yaw: float = 360
|
||||
|
||||
@export var run_noise: PhantomCameraNoise3D
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"):
|
||||
%EmitterTip.visible = true
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
super(delta)
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event is InputEventKey:
|
||||
if get_node_or_null("%PlayerPhantomCameraNoiseEmitter3D"):
|
||||
if event.keycode == KEY_Q and event.is_pressed():
|
||||
%PlayerPhantomCameraNoiseEmitter3D.emit()
|
||||
|
||||
if event is InputEventMouseMotion:
|
||||
var pcam_rotation_degrees: Vector3
|
||||
|
||||
# Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor
|
||||
pcam_rotation_degrees = _player_pcam.rotation_degrees
|
||||
|
||||
# Change the X rotation
|
||||
pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity
|
||||
|
||||
# Clamp the rotation in the X axis so it go over or under the target
|
||||
pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch)
|
||||
|
||||
# Change the Y rotation value
|
||||
pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity
|
||||
|
||||
# Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively
|
||||
pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw)
|
||||
|
||||
# Change the SpringArm3D node's rotation and rotate around its target
|
||||
_player_pcam.rotation_degrees = pcam_rotation_degrees
|
@@ -0,0 +1,87 @@
|
||||
extends "player_controller.gd"
|
||||
|
||||
@onready var _player_pcam: PhantomCamera3D
|
||||
@onready var _aim_pcam: PhantomCamera3D
|
||||
@onready var _player_direction: Node3D = %PlayerDirection
|
||||
@onready var _ceiling_pcam: PhantomCamera3D
|
||||
|
||||
@export var mouse_sensitivity: float = 0.05
|
||||
|
||||
@export var min_pitch: float = -89.9
|
||||
@export var max_pitch: float = 50
|
||||
|
||||
@export var min_yaw: float = 0
|
||||
@export var max_yaw: float = 360
|
||||
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
|
||||
_player_pcam = owner.get_node("%PlayerPhantomCamera3D")
|
||||
_aim_pcam = owner.get_node("%PlayerAimPhantomCamera3D")
|
||||
_ceiling_pcam = owner.get_node("%CeilingPhantomCamera3D")
|
||||
|
||||
if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
super(delta)
|
||||
|
||||
if velocity.length() > 0.2:
|
||||
var look_direction: Vector2 = Vector2(velocity.z, velocity.x)
|
||||
_player_direction.rotation.y = look_direction.angle()
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON:
|
||||
var active_pcam: PhantomCamera3D
|
||||
|
||||
_set_pcam_rotation(_player_pcam, event)
|
||||
_set_pcam_rotation(_aim_pcam, event)
|
||||
if _player_pcam.get_priority() > _aim_pcam.get_priority():
|
||||
_toggle_aim_pcam(event)
|
||||
else:
|
||||
_toggle_aim_pcam(event)
|
||||
|
||||
if event is InputEventKey and event.pressed:
|
||||
if event.keycode == KEY_SPACE:
|
||||
if _ceiling_pcam.get_priority() < 30 and _player_pcam.is_active():
|
||||
_ceiling_pcam.set_priority(30)
|
||||
else:
|
||||
_ceiling_pcam.set_priority(1)
|
||||
|
||||
|
||||
func _set_pcam_rotation(pcam: PhantomCamera3D, event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
var pcam_rotation_degrees: Vector3
|
||||
|
||||
# Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor
|
||||
pcam_rotation_degrees = pcam.get_third_person_rotation_degrees()
|
||||
|
||||
# Change the X rotation
|
||||
pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity
|
||||
|
||||
# Clamp the rotation in the X axis so it go over or under the target
|
||||
pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch)
|
||||
|
||||
# Change the Y rotation value
|
||||
pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity
|
||||
|
||||
# Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively
|
||||
pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw)
|
||||
|
||||
# Change the SpringArm3D node's rotation and rotate around its target
|
||||
pcam.set_third_person_rotation_degrees(pcam_rotation_degrees)
|
||||
|
||||
|
||||
func _toggle_aim_pcam(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton \
|
||||
and event.is_pressed() \
|
||||
and event.button_index == 2 \
|
||||
and (_player_pcam.is_active() or _aim_pcam.is_active()):
|
||||
if _player_pcam.get_priority() > _aim_pcam.get_priority():
|
||||
_aim_pcam.set_priority(30)
|
||||
else:
|
||||
_aim_pcam.set_priority(0)
|
@@ -0,0 +1,85 @@
|
||||
extends "player_controller_4.4.gd"
|
||||
|
||||
@onready var _player_pcam: PhantomCamera3D
|
||||
@onready var _aim_pcam: PhantomCamera3D
|
||||
@onready var _player_direction: Node3D = %PlayerDirection
|
||||
@onready var _ceiling_pcam: PhantomCamera3D
|
||||
|
||||
@export var mouse_sensitivity: float = 0.05
|
||||
|
||||
@export var min_pitch: float = -89.9
|
||||
@export var max_pitch: float = 50
|
||||
|
||||
@export var min_yaw: float = 0
|
||||
@export var max_yaw: float = 360
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
super()
|
||||
|
||||
_player_pcam = owner.get_node("%PlayerPhantomCamera3D")
|
||||
_aim_pcam = owner.get_node("%PlayerAimPhantomCamera3D")
|
||||
_ceiling_pcam = owner.get_node("%CeilingPhantomCamera3D")
|
||||
|
||||
if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON:
|
||||
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
super(delta)
|
||||
|
||||
if velocity.length() > 0.2:
|
||||
var look_direction: Vector2 = Vector2(velocity.z, velocity.x)
|
||||
_player_direction.rotation.y = look_direction.angle()
|
||||
|
||||
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if _player_pcam.get_follow_mode() == _player_pcam.FollowMode.THIRD_PERSON:
|
||||
var active_pcam: PhantomCamera3D
|
||||
|
||||
_set_pcam_rotation(_player_pcam, event)
|
||||
_set_pcam_rotation(_aim_pcam, event)
|
||||
if _player_pcam.get_priority() > _aim_pcam.get_priority():
|
||||
_toggle_aim_pcam(event)
|
||||
else:
|
||||
_toggle_aim_pcam(event)
|
||||
|
||||
if event is InputEventKey and event.pressed:
|
||||
if event.keycode == KEY_SPACE:
|
||||
if _ceiling_pcam.get_priority() < 30 and _player_pcam.is_active():
|
||||
_ceiling_pcam.set_priority(30)
|
||||
else:
|
||||
_ceiling_pcam.set_priority(1)
|
||||
|
||||
|
||||
func _set_pcam_rotation(pcam: PhantomCamera3D, event: InputEvent) -> void:
|
||||
if event is InputEventMouseMotion:
|
||||
var pcam_rotation_degrees: Vector3
|
||||
|
||||
# Assigns the current 3D rotation of the SpringArm3D node - so it starts off where it is in the editor
|
||||
pcam_rotation_degrees = pcam.get_third_person_rotation_degrees()
|
||||
|
||||
# Change the X rotation
|
||||
pcam_rotation_degrees.x -= event.relative.y * mouse_sensitivity
|
||||
|
||||
# Clamp the rotation in the X axis so it go over or under the target
|
||||
pcam_rotation_degrees.x = clampf(pcam_rotation_degrees.x, min_pitch, max_pitch)
|
||||
|
||||
# Change the Y rotation value
|
||||
pcam_rotation_degrees.y -= event.relative.x * mouse_sensitivity
|
||||
|
||||
# Sets the rotation to fully loop around its target, but witout going below or exceeding 0 and 360 degrees respectively
|
||||
pcam_rotation_degrees.y = wrapf(pcam_rotation_degrees.y, min_yaw, max_yaw)
|
||||
|
||||
# Change the SpringArm3D node's rotation and rotate around its target
|
||||
pcam.set_third_person_rotation_degrees(pcam_rotation_degrees)
|
||||
|
||||
|
||||
func _toggle_aim_pcam(event: InputEvent) -> void:
|
||||
if event is InputEventMouseButton \
|
||||
and event.is_pressed() \
|
||||
and event.button_index == 2 \
|
||||
and (_player_pcam.is_active() or _aim_pcam.is_active()):
|
||||
if _player_pcam.get_priority() > _aim_pcam.get_priority():
|
||||
_aim_pcam.set_priority(30)
|
||||
else:
|
||||
_aim_pcam.set_priority(0)
|
Reference in New Issue
Block a user