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
|
Reference in New Issue
Block a user