GDScript formatting
Thanks, VS Code (:
This commit is contained in:
parent
1e100bee4d
commit
42490ddad9
@ -11,16 +11,16 @@ extends Area3D
|
||||
class_name AdvancedPortalTeleport
|
||||
|
||||
## Checks if the node is moving TOWARDS the portal before teleporting it.
|
||||
@export var velocity_check:bool = true
|
||||
@export var velocity_check: bool = true
|
||||
## An additional velocity push given to RigidBody3Ds/CharacterBody3D exiting the portal.
|
||||
@export var exit_push_velocity:float = 0
|
||||
@export var exit_push_velocity: float = 0
|
||||
## Seconds to keep portal clones visible after the node leaves the teleporter.
|
||||
@export var clone_keep_alive_seconds:float = 0.1
|
||||
@export var clone_keep_alive_seconds: float = 0.1
|
||||
|
||||
var _parent_portal:Portal
|
||||
var _parent_portal: Portal
|
||||
|
||||
# Info about the nodes currently crossing the portal
|
||||
var _crossing_nodes:Array = []
|
||||
var _crossing_nodes: Array = []
|
||||
|
||||
func _ready() -> void:
|
||||
_parent_portal = get_parent() as Portal
|
||||
@ -30,10 +30,10 @@ func _ready() -> void:
|
||||
connect("area_entered", _on_area_entered)
|
||||
connect("area_exited", _on_area_exited)
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
# Update nodes crossing the portal
|
||||
for i in range(_crossing_nodes.size() - 1, -1, -1):
|
||||
var crossing_node:Dictionary = _crossing_nodes[i]
|
||||
var crossing_node: Dictionary = _crossing_nodes[i]
|
||||
|
||||
if not is_instance_valid(crossing_node.node):
|
||||
# Node has been freed, remove crossing_node
|
||||
@ -61,17 +61,17 @@ func _process(delta:float) -> void:
|
||||
_crossing_nodes.remove_at(i)
|
||||
|
||||
# Try to teleport the crossing node, and return false otherwise
|
||||
func _try_teleport(crossing_node:Dictionary) -> bool:
|
||||
var node:Node3D = crossing_node.node
|
||||
func _try_teleport(crossing_node: Dictionary) -> bool:
|
||||
var node: Node3D = crossing_node.node
|
||||
|
||||
# Check if the node is moving towards the portal
|
||||
if velocity_check:
|
||||
if node is RigidBody3D:
|
||||
var local_velocity:Vector3 = _parent_portal.global_transform.basis.inverse() * node.linear_velocity
|
||||
var local_velocity: Vector3 = _parent_portal.global_transform.basis.inverse() * node.linear_velocity
|
||||
if local_velocity.z >= 0:
|
||||
return false
|
||||
elif node is CharacterBody3D:
|
||||
var local_velocity:Vector3 = _parent_portal.global_transform.basis.inverse() * node.velocity
|
||||
var local_velocity: Vector3 = _parent_portal.global_transform.basis.inverse() * node.velocity
|
||||
if local_velocity.z >= 0:
|
||||
return false
|
||||
else:
|
||||
@ -88,7 +88,7 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
|
||||
|
||||
# Additional push when exiting the portal
|
||||
if exit_push_velocity > 0:
|
||||
var exit_forward:Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
|
||||
var exit_forward: Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
|
||||
node.linear_velocity += exit_forward * exit_push_velocity
|
||||
|
||||
# Handle CharacterBody3D physics
|
||||
@ -98,7 +98,7 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
|
||||
|
||||
# Additional push when exiting the portal
|
||||
if exit_push_velocity > 0:
|
||||
var exit_forward:Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
|
||||
var exit_forward: Vector3 = _parent_portal.exit_portal.global_transform.basis.z.normalized()
|
||||
node.velocity += exit_forward * exit_push_velocity
|
||||
|
||||
# Transform the position and orientation
|
||||
@ -106,22 +106,21 @@ func _try_teleport(crossing_node:Dictionary) -> bool:
|
||||
|
||||
return true
|
||||
|
||||
func _on_area_entered(area:Area3D) -> void:
|
||||
func _on_area_entered(area: Area3D) -> void:
|
||||
if area.has_meta("teleportable_root"):
|
||||
# The node may not teleport immediately if it's not heading TOWARDS the portal,
|
||||
# so we keep a reference to it until it teleports or leaves.
|
||||
# This also allows us to hide its portal clone after it leaves.
|
||||
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
|
||||
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
|
||||
var crossing_node:Dictionary
|
||||
var crossing_node: Dictionary
|
||||
if root.has_meta("crossing_node"):
|
||||
# Node is crossing another portal, erase it from that portal and start using this one instead
|
||||
crossing_node = root.get_meta("crossing_node")
|
||||
crossing_node.teleporter._crossing_nodes.erase(crossing_node)
|
||||
else:
|
||||
# First portal
|
||||
var clone:Node3D = area.get_node(area.get_meta("portal_clone")) if area.has_meta("portal_clone") else null
|
||||
var clone: Node3D = area.get_node(area.get_meta("portal_clone")) if area.has_meta("portal_clone") else null
|
||||
crossing_node = {
|
||||
"node": root,
|
||||
"clone": clone,
|
||||
@ -151,10 +150,10 @@ func _on_area_entered(area:Area3D) -> void:
|
||||
crossing_node.clone_portal = _parent_portal.exit_portal
|
||||
crossing_node.left = true
|
||||
|
||||
func _on_area_exited(area:Area3D) -> void:
|
||||
func _on_area_exited(area: Area3D) -> void:
|
||||
if area.has_meta("teleportable_root"):
|
||||
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
var crossing_node:Dictionary = root.get_meta("crossing_node")
|
||||
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
var crossing_node: Dictionary = root.get_meta("crossing_node")
|
||||
|
||||
if crossing_node.teleporter == self:
|
||||
# The node left the enter portal without teleporting (but don't erase it yet)
|
||||
|
@ -11,18 +11,18 @@ extends Area3D
|
||||
class_name CollisionDisableArea
|
||||
|
||||
## Seconds until collisions are re-enabled after the body leaves the area.
|
||||
@export var re_enable_delay_seconds:float = 0.1
|
||||
@export var re_enable_delay_seconds: float = 0.1
|
||||
|
||||
# Info about the disabled bodies
|
||||
var _disables:Array = []
|
||||
var _disables: Array = []
|
||||
|
||||
func _ready() -> void:
|
||||
connect("body_entered", _on_body_entered)
|
||||
connect("body_exited", _on_body_exited)
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
for i in range(_disables.size() - 1, -1, -1):
|
||||
var disable_info:Dictionary = _disables[i]
|
||||
var disable_info: Dictionary = _disables[i]
|
||||
|
||||
if not is_instance_valid(disable_info.body):
|
||||
# Body has been freed, remove disable info
|
||||
@ -50,7 +50,7 @@ func _process(delta:float) -> void:
|
||||
# Final disable, so re-enable the collision mask
|
||||
disable_info.body.set_collision_mask_value(layer_number, true)
|
||||
|
||||
func _on_body_entered(body:PhysicsBody3D) -> void:
|
||||
func _on_body_entered(body: PhysicsBody3D) -> void:
|
||||
if not body.has_meta("disabled_collision_masks"):
|
||||
return
|
||||
|
||||
@ -65,10 +65,10 @@ func _on_body_entered(body:PhysicsBody3D) -> void:
|
||||
# Keep track of the number of times each collision mask is disabled in a meta field
|
||||
if not body.has_meta("collision_disable_count"):
|
||||
body.set_meta("collision_disable_count", {})
|
||||
var disable_count:Dictionary = body.get_meta("collision_disable_count")
|
||||
var disable_count: Dictionary = body.get_meta("collision_disable_count")
|
||||
|
||||
# Disable the collision masks specified in the "disabled_collision_masks" metadata array
|
||||
var disabled_layers:Array = body.get_meta("disabled_collision_masks")
|
||||
var disabled_layers: Array = body.get_meta("disabled_collision_masks")
|
||||
for layer_number in disabled_layers:
|
||||
# Only consider layers which were enabled to begin with
|
||||
if disable_count.has(layer_number) or body.get_collision_mask_value(layer_number):
|
||||
@ -87,7 +87,7 @@ func _on_body_entered(body:PhysicsBody3D) -> void:
|
||||
"left": false,
|
||||
})
|
||||
|
||||
func _on_body_exited(body:PhysicsBody3D) -> void:
|
||||
func _on_body_exited(body: PhysicsBody3D) -> void:
|
||||
if body.has_meta("disabled_collision_masks"):
|
||||
for disable_info in _disables:
|
||||
if disable_info.body == body:
|
||||
|
@ -9,16 +9,16 @@
|
||||
extends RigidBody3D
|
||||
class_name Hoverable
|
||||
|
||||
@onready var _mesh:MeshInstance3D = $Mesh
|
||||
@onready var _mesh: MeshInstance3D = $Mesh
|
||||
|
||||
var hovered:bool
|
||||
var hovered: bool
|
||||
|
||||
var _strength:float
|
||||
var _strength: float
|
||||
|
||||
func _ready() -> void:
|
||||
_mesh.material_override = _mesh.mesh.surface_get_material(0).duplicate()
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
_strength = min(1, _strength + delta * 10) if hovered else max(0, _strength - delta * 10)
|
||||
|
||||
_mesh.material_override.albedo_color = lerp(Color.WHITE, Color.RED, _strength)
|
||||
|
@ -9,15 +9,15 @@
|
||||
extends MeshInstance3D
|
||||
class_name LineRenderer
|
||||
|
||||
@export var material:Material
|
||||
@export var material: Material
|
||||
|
||||
var _lines:Array
|
||||
var _dirty:bool
|
||||
var _lines: Array
|
||||
var _dirty: bool
|
||||
|
||||
func _ready() -> void:
|
||||
mesh = ImmediateMesh.new()
|
||||
|
||||
func add_line(from:Vector3, to:Vector3, color:Color = Color.WHITE) -> void:
|
||||
func add_line(from: Vector3, to: Vector3, color: Color = Color.WHITE) -> void:
|
||||
_lines.push_back([from, to, color])
|
||||
_dirty = true
|
||||
|
||||
@ -25,7 +25,7 @@ func clear_lines() -> void:
|
||||
_lines.clear()
|
||||
_dirty = true
|
||||
|
||||
func _process(_delta:float) -> void:
|
||||
func _process(_delta: float) -> void:
|
||||
if not _dirty:
|
||||
return
|
||||
_dirty = false
|
||||
|
@ -8,18 +8,18 @@
|
||||
|
||||
extends MeshInstance3D
|
||||
|
||||
const _MOUSE_PAN_THRESHOLD:float = 0.4;
|
||||
const _MOUSE_PAN_SPEED:float = 200
|
||||
const _MOUSE_PAN_THRESHOLD: float = 0.4;
|
||||
const _MOUSE_PAN_SPEED: float = 200
|
||||
|
||||
const _MOVE_SPEED:float = 4
|
||||
const _MOVE_SPEED: float = 4
|
||||
|
||||
var _mouse_look:Vector2
|
||||
var _mouse_look: Vector2
|
||||
|
||||
@onready var _line_renderer:LineRenderer = $"../LineRenderer"
|
||||
@onready var _camera:Camera3D = $Camera
|
||||
@onready var _pip_camera:Camera3D = $PipViewport1/Camera
|
||||
@onready var _line_renderer: LineRenderer = $"../LineRenderer"
|
||||
@onready var _camera: Camera3D = $Camera
|
||||
@onready var _pip_camera: Camera3D = $PipViewport1/Camera
|
||||
|
||||
@onready var _handle_raycast_callable:Callable = Callable(self, "_handle_raycast")
|
||||
@onready var _handle_raycast_callable: Callable = Callable(self, "_handle_raycast")
|
||||
|
||||
func _ready() -> void:
|
||||
set_layer_mask_value(1, false)
|
||||
@ -27,16 +27,16 @@ func _ready() -> void:
|
||||
|
||||
_camera.set_cull_mask_value(2, false)
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
var viewport:Viewport = get_viewport()
|
||||
var mouse_position:Vector2 = viewport.get_mouse_position()
|
||||
var viewport_size:Vector2i = viewport.size
|
||||
var normalized_mouse_position:Vector2 = mouse_position / Vector2(viewport_size)
|
||||
func _process(delta: float) -> void:
|
||||
var viewport: Viewport = get_viewport()
|
||||
var mouse_position: Vector2 = viewport.get_mouse_position()
|
||||
var viewport_size: Vector2i = viewport.size
|
||||
var normalized_mouse_position: Vector2 = mouse_position / Vector2(viewport_size)
|
||||
|
||||
var horizontal_speed:float = 0
|
||||
var vertical_speed:float = 0
|
||||
var horizontal_speed: float = 0
|
||||
var vertical_speed: float = 0
|
||||
|
||||
if normalized_mouse_position.x > 0 and normalized_mouse_position.x < 1 and\
|
||||
if normalized_mouse_position.x > 0 and normalized_mouse_position.x < 1 and \
|
||||
normalized_mouse_position.y > 0 and normalized_mouse_position.y < 1:
|
||||
if normalized_mouse_position.x < _MOUSE_PAN_THRESHOLD:
|
||||
horizontal_speed = lerp(0, 1, _MOUSE_PAN_THRESHOLD - normalized_mouse_position.x)
|
||||
@ -53,15 +53,15 @@ func _process(delta:float) -> void:
|
||||
rotation_degrees = Vector3(0, _mouse_look.x, 0)
|
||||
_camera.rotation_degrees = Vector3(_mouse_look.y, 0, 0)
|
||||
|
||||
var right:Vector3 = (global_transform.basis.x * Vector3(1, 0, 1)).normalized()
|
||||
var forward:Vector3 = (global_transform.basis.z * Vector3(1, 0, 1)).normalized()
|
||||
var right: Vector3 = (global_transform.basis.x * Vector3(1, 0, 1)).normalized()
|
||||
var forward: Vector3 = (global_transform.basis.z * Vector3(1, 0, 1)).normalized()
|
||||
|
||||
if Input.is_key_pressed(KEY_LEFT) or Input.is_key_pressed(KEY_A):
|
||||
global_translate(-right * _MOVE_SPEED * delta)
|
||||
global_translate(- right * _MOVE_SPEED * delta)
|
||||
if Input.is_key_pressed(KEY_RIGHT) or Input.is_key_pressed(KEY_D):
|
||||
global_translate(right * _MOVE_SPEED * delta)
|
||||
if Input.is_key_pressed(KEY_UP) or Input.is_key_pressed(KEY_W):
|
||||
global_translate(-forward * _MOVE_SPEED * delta)
|
||||
global_translate(- forward * _MOVE_SPEED * delta)
|
||||
if Input.is_key_pressed(KEY_DOWN) or Input.is_key_pressed(KEY_S):
|
||||
global_translate(forward * _MOVE_SPEED * delta)
|
||||
|
||||
@ -75,16 +75,16 @@ func _process(delta:float) -> void:
|
||||
_pip_camera.global_position = _camera.to_global(Vector3(0, 1.5, 1.5))
|
||||
_pip_camera.global_rotation = _camera.global_rotation
|
||||
|
||||
var origin:Vector3 = _camera.project_ray_origin(mouse_position)
|
||||
var end:Vector3 = origin + _camera.project_ray_normal(mouse_position) * 100
|
||||
var origin: Vector3 = _camera.project_ray_origin(mouse_position)
|
||||
var end: Vector3 = origin + _camera.project_ray_normal(mouse_position) * 100
|
||||
|
||||
_line_renderer.clear_lines()
|
||||
|
||||
Portal.raycast(get_tree(), origin, (end - origin).normalized(), _handle_raycast_callable)
|
||||
|
||||
func _handle_raycast(from:Vector3, dir:Vector3, segment_distance:float, _recursive_distance:float, recursions:int) -> bool:
|
||||
var distance:float = min(100, segment_distance)
|
||||
var target:Vector3 = from + dir * distance
|
||||
func _handle_raycast(from: Vector3, dir: Vector3, segment_distance: float, _recursive_distance: float, recursions: int) -> bool:
|
||||
var distance: float = min(100, segment_distance)
|
||||
var target: Vector3 = from + dir * distance
|
||||
|
||||
_line_renderer.add_line(from, target, Color.GREEN)
|
||||
for i in 16:
|
||||
@ -98,9 +98,9 @@ func _handle_raycast(from:Vector3, dir:Vector3, segment_distance:float, _recursi
|
||||
randf_range(-0.1, 0.1),
|
||||
randf_range(-0.1, 0.1)), Color.BLUE)
|
||||
|
||||
var space_state:PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
|
||||
var query:PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, from + dir * distance)
|
||||
var result:Dictionary = space_state.intersect_ray(query)
|
||||
var space_state: PhysicsDirectSpaceState3D = get_world_3d().direct_space_state
|
||||
var query: PhysicsRayQueryParameters3D = PhysicsRayQueryParameters3D.create(from, from + dir * distance)
|
||||
var result: Dictionary = space_state.intersect_ray(query)
|
||||
if not result.is_empty() and result.collider is Hoverable:
|
||||
result.collider.hovered = true
|
||||
for i in 16:
|
||||
|
@ -12,56 +12,56 @@ class_name Portal
|
||||
## The portal represents a single portal mesh in a pair of portals.
|
||||
|
||||
## The delay between the main viewport changing size and the portal viewport resizing.
|
||||
const _RESIZE_THROTTLE_SECONDS:float = 0.1
|
||||
const _RESIZE_THROTTLE_SECONDS: float = 0.1
|
||||
|
||||
## The minimum camera near clipping distance.
|
||||
const _EXIT_CAMERA_NEAR_MIN:float = 0.01
|
||||
const _EXIT_CAMERA_NEAR_MIN: float = 0.01
|
||||
|
||||
## The portal mesh's local bounding box.
|
||||
@onready var _mesh_aabb:AABB = mesh.get_aabb()
|
||||
@onready var _mesh_aabb: AABB = mesh.get_aabb()
|
||||
|
||||
## The vertical resolution of the portal viewport which covers the entire screen not just the portal mesh. Use 0 to use the real resolution.
|
||||
@export var vertical_viewport_resolution:int = 512
|
||||
@export var vertical_viewport_resolution: int = 512
|
||||
|
||||
## Disable viewport distance. Portals further away than this won't have their viewports rendered.
|
||||
@export var disable_viewport_distance:float = 11
|
||||
@export var disable_viewport_distance: float = 11
|
||||
## Whether to destroy the disabled viewport to save texture memory. Useful when you have a lot of portals. The viewport is re/-created when within disable_viewport_distance and visible.
|
||||
@export var destroy_disabled_viewport:bool = true
|
||||
@export var destroy_disabled_viewport: bool = true
|
||||
|
||||
## The maximum fade-out distance.
|
||||
@export var fade_out_distance_max:float = 10
|
||||
@export var fade_out_distance_max: float = 10
|
||||
## The minimum fade-out distance.
|
||||
@export var fade_out_distance_min:float = 8
|
||||
@export var fade_out_distance_min: float = 8
|
||||
## The fade-out color.
|
||||
@export var fade_out_color:Color = Color.WHITE
|
||||
@export var fade_out_color: Color = Color.WHITE
|
||||
|
||||
## The scale of the exit side of the portal. < 1 means the exit is smaller than the entrance.
|
||||
@export var exit_scale:float = 1.0
|
||||
@export var exit_scale: float = 1.0
|
||||
## A value subtracted from the exit camera near clipping plane. Useful for handling clipping issues.
|
||||
@export var exit_near_subtract:float = 0.05
|
||||
@export var exit_near_subtract: float = 0.05
|
||||
|
||||
## The main camera. Leave unset to use the default 3D camera.
|
||||
@export var main_camera:Camera3D
|
||||
@export var main_camera: Camera3D
|
||||
|
||||
## An environment set for the exit camera. Leave unset to use the default environment.
|
||||
@export var exit_environment:Environment
|
||||
@export var exit_environment: Environment
|
||||
## The cull mask for the exit camera. Use it to hide certain objects in the exit camera.
|
||||
@export_flags_3d_render var exit_cull_mask:int = 0b11111111111111111111
|
||||
@export_flags_3d_render var exit_cull_mask: int = 0b11111111111111111111
|
||||
|
||||
## The exit portal. Leave unset to use this portal as an exit only.
|
||||
@export var exit_portal:Portal
|
||||
@export var exit_portal: Portal
|
||||
|
||||
## An environment set for the exit camera. Leave unset to use the default environment.
|
||||
@export var portal_shader:Shader = preload("res://addons/simple-portal-system/shaders/portal.gdshader")
|
||||
@export var portal_shader: Shader = preload("res://addons/simple-portal-system/shaders/portal.gdshader")
|
||||
|
||||
# The viewport rendering the portal surface
|
||||
var _viewport:SubViewport
|
||||
var _viewport: SubViewport
|
||||
|
||||
# The exit camera copies the main camera's position relative to the exit portal
|
||||
var _exit_camera:Camera3D
|
||||
var _exit_camera: Camera3D
|
||||
|
||||
# The number of seconds until the viewport updates its size
|
||||
var _seconds_until_resize:float
|
||||
var _seconds_until_resize: float
|
||||
|
||||
func _enter_tree() -> void:
|
||||
add_to_group("portals")
|
||||
@ -81,7 +81,7 @@ func _ready() -> void:
|
||||
|
||||
# Non-uniform parent scaling can introduce skew which isn't compensated for
|
||||
if get_parent() != null:
|
||||
var parent_scale:Vector3 = get_parent().global_transform.basis.get_scale()
|
||||
var parent_scale: Vector3 = get_parent().global_transform.basis.get_scale()
|
||||
if abs(parent_scale.x - parent_scale.y) > 0.01 or abs(parent_scale.x - parent_scale.z) > 0.01:
|
||||
push_warning("The parent of \"%s\" is not uniformly scaled. The portal will not work correctly." % name)
|
||||
|
||||
@ -105,7 +105,7 @@ func _ready() -> void:
|
||||
# Create the viewport when _ready if it's not destroyed when disabled.
|
||||
# This may potentially get rid of the initial lag when the viewport is first created at the cost of texture memory.
|
||||
if not destroy_disabled_viewport:
|
||||
_create_viewport()
|
||||
_createa_viewport()
|
||||
|
||||
get_viewport().connect("size_changed", _handle_resize)
|
||||
|
||||
@ -130,9 +130,9 @@ func _create_viewport() -> void:
|
||||
# Resize the viewport on the next _process
|
||||
_seconds_until_resize = 0
|
||||
|
||||
func _process(delta:float) -> void:
|
||||
func _process(delta: float) -> void:
|
||||
# Disable the viewport if the portal is further away than disable_viewport_distance or if the portal is invisible in the scene tree
|
||||
var disable_viewport:bool = not is_visible_in_tree() or\
|
||||
var disable_viewport: bool = not is_visible_in_tree() or \
|
||||
main_camera.global_position.distance_squared_to(global_position) > disable_viewport_distance * disable_viewport_distance
|
||||
|
||||
# Enable or disable 3D rendering for the viewport (if it exists)
|
||||
@ -163,13 +163,13 @@ func _process(delta:float) -> void:
|
||||
if _seconds_until_resize <= 0:
|
||||
_seconds_until_resize = NAN
|
||||
|
||||
var viewport_size:Vector2i = get_viewport().size
|
||||
var viewport_size: Vector2i = get_viewport().size
|
||||
if vertical_viewport_resolution == 0:
|
||||
# Resize the viewport to the main viewport size
|
||||
_viewport.size = viewport_size
|
||||
else:
|
||||
# Resize the viewport to the fixed height vertical_viewport_resolution and dynamic width
|
||||
var aspect_ratio:float = float(viewport_size.x) / viewport_size.y
|
||||
var aspect_ratio: float = float(viewport_size.x) / viewport_size.y
|
||||
_viewport.size = Vector2i(int(vertical_viewport_resolution * aspect_ratio + 0.5), vertical_viewport_resolution)
|
||||
|
||||
# Move the exit camera relative to the exit portal based on the main camera's position relative to the entrance portal
|
||||
@ -177,18 +177,18 @@ func _process(delta:float) -> void:
|
||||
|
||||
# Get the four X, Y corners of the scaled entrance portal bounding box clamped to Z=0 (portal surface) relative to the exit portal.
|
||||
# The entrance portal bounding box is used since the entrance portal mesh does not need to match the exit portal mesh.
|
||||
var corner_1:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y, 0) * exit_scale)
|
||||
var corner_2:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y, 0) * exit_scale)
|
||||
var corner_3:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
|
||||
var corner_4:Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
|
||||
var corner_1: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y, 0) * exit_scale)
|
||||
var corner_2: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y, 0) * exit_scale)
|
||||
var corner_3: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x + _mesh_aabb.size.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
|
||||
var corner_4: Vector3 = exit_portal.to_global(Vector3(_mesh_aabb.position.x, _mesh_aabb.position.y + _mesh_aabb.size.y, 0) * exit_scale)
|
||||
|
||||
# Calculate the distance along the exit camera forward vector at which each of the portal corners projects
|
||||
var camera_forward:Vector3 = -_exit_camera.global_transform.basis.z.normalized()
|
||||
var camera_forward: Vector3 = - _exit_camera.global_transform.basis.z.normalized()
|
||||
|
||||
var d_1:float = (corner_1 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_2:float = (corner_2 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_3:float = (corner_3 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_4:float = (corner_4 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_1: float = (corner_1 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_2: float = (corner_2 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_3: float = (corner_3 - _exit_camera.global_position).dot(camera_forward)
|
||||
var d_4: float = (corner_4 - _exit_camera.global_position).dot(camera_forward)
|
||||
|
||||
# The near clip distance is the shortest distance which still contains all the corners
|
||||
_exit_camera.near = max(_EXIT_CAMERA_NEAR_MIN, min(d_1, d_2, d_3, d_4) - exit_near_subtract)
|
||||
@ -197,60 +197,60 @@ func _process(delta:float) -> void:
|
||||
_exit_camera.keep_aspect = main_camera.keep_aspect
|
||||
|
||||
## Return a new Transform3D relative to the exit portal based on the real Transform3D relative to this portal.
|
||||
func real_to_exit_transform(real:Transform3D) -> Transform3D:
|
||||
func real_to_exit_transform(real: Transform3D) -> Transform3D:
|
||||
# Convert from global space to local space at the entrance (this) portal
|
||||
var local:Transform3D = global_transform.affine_inverse() * real
|
||||
var local: Transform3D = global_transform.affine_inverse() * real
|
||||
# Compensate for any scale the entrance portal may have
|
||||
var unscaled:Transform3D = local.scaled(global_transform.basis.get_scale())
|
||||
var unscaled: Transform3D = local.scaled(global_transform.basis.get_scale())
|
||||
# Flip it (the portal always flips the view 180 degrees)
|
||||
var flipped:Transform3D = unscaled.rotated(Vector3.UP, PI)
|
||||
var flipped: Transform3D = unscaled.rotated(Vector3.UP, PI)
|
||||
# Apply any scale the exit portal may have (and apply custom exit scale)
|
||||
var exit_scale_vector:Vector3 = exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit:Transform3D = flipped.scaled(Vector3.ONE / exit_scale_vector * exit_scale)
|
||||
var exit_scale_vector: Vector3 = exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit: Transform3D = flipped.scaled(Vector3.ONE / exit_scale_vector * exit_scale)
|
||||
# Convert from local space at the exit portal to global space
|
||||
var local_at_exit:Transform3D = exit_portal.global_transform * scaled_at_exit
|
||||
var local_at_exit: Transform3D = exit_portal.global_transform * scaled_at_exit
|
||||
return local_at_exit
|
||||
|
||||
## Return a new position relative to the exit portal based on the real position relative to this portal.
|
||||
func real_to_exit_position(real:Vector3) -> Vector3:
|
||||
func real_to_exit_position(real: Vector3) -> Vector3:
|
||||
# Convert from global space to local space at the entrance (this) portal
|
||||
var local:Vector3 = global_transform.affine_inverse() * real
|
||||
var local: Vector3 = global_transform.affine_inverse() * real
|
||||
# Compensate for any scale the entrance portal may have
|
||||
var unscaled:Vector3 = local * global_transform.basis.get_scale()
|
||||
var unscaled: Vector3 = local * global_transform.basis.get_scale()
|
||||
# Apply any scale the exit portal may have (and apply custom exit scale)
|
||||
var exit_scale_vector:Vector3 = Vector3(-1, 1, 1) * exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit:Vector3 = unscaled / exit_scale_vector * exit_scale
|
||||
var exit_scale_vector: Vector3 = Vector3(-1, 1, 1) * exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit: Vector3 = unscaled / exit_scale_vector * exit_scale
|
||||
# Convert from local space at the exit portal to global space
|
||||
var local_at_exit:Vector3 = exit_portal.global_transform * scaled_at_exit
|
||||
var local_at_exit: Vector3 = exit_portal.global_transform * scaled_at_exit
|
||||
return local_at_exit
|
||||
|
||||
## Return a new direction relative to the exit portal based on the real direction relative to this portal.
|
||||
func real_to_exit_direction(real:Vector3) -> Vector3:
|
||||
func real_to_exit_direction(real: Vector3) -> Vector3:
|
||||
# Convert from global to local space at the entrance (this) portal
|
||||
var local:Vector3 = global_transform.basis.inverse() * real
|
||||
var local: Vector3 = global_transform.basis.inverse() * real
|
||||
# Compensate for any scale the entrance portal may have
|
||||
var unscaled:Vector3 = local * global_transform.basis.get_scale()
|
||||
var unscaled: Vector3 = local * global_transform.basis.get_scale()
|
||||
# Flip it (the portal always flips the view 180 degrees)
|
||||
var flipped:Vector3 = unscaled.rotated(Vector3.UP, PI)
|
||||
var flipped: Vector3 = unscaled.rotated(Vector3.UP, PI)
|
||||
# Apply any scale the exit portal may have (and apply custom exit scale)
|
||||
var exit_scale_vector:Vector3 = exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit:Vector3 = flipped / exit_scale_vector * exit_scale
|
||||
var exit_scale_vector: Vector3 = exit_portal.global_transform.basis.get_scale()
|
||||
var scaled_at_exit: Vector3 = flipped / exit_scale_vector * exit_scale
|
||||
# Convert from local space at the exit portal to global space
|
||||
var local_at_exit:Vector3 = exit_portal.global_transform.basis * scaled_at_exit
|
||||
var local_at_exit: Vector3 = exit_portal.global_transform.basis * scaled_at_exit
|
||||
return local_at_exit
|
||||
|
||||
## Raycast against portals (See instructions).
|
||||
static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Callable,
|
||||
max_distance:float = INF, max_recursions:int = 16, ignore_backside:bool = true) -> void:
|
||||
var portals:Array = tree.get_nodes_in_group("portals")
|
||||
var ignore_portal:Portal = null
|
||||
var recursive_distance:float = 0
|
||||
static func raycast(tree: SceneTree, from: Vector3, dir: Vector3, handle_raycast: Callable,
|
||||
max_distance: float = INF, max_recursions: int = 16, ignore_backside: bool = true) -> void:
|
||||
var portals: Array = tree.get_nodes_in_group("portals")
|
||||
var ignore_portal: Portal = null
|
||||
var recursive_distance: float = 0
|
||||
|
||||
for r in max_recursions + 1:
|
||||
var closest_hit:Vector3
|
||||
var closest_dir:Vector3
|
||||
var closest_portal:Portal
|
||||
var closest_distance_sqr:float = INF
|
||||
var closest_hit: Vector3
|
||||
var closest_dir: Vector3
|
||||
var closest_portal: Portal
|
||||
var closest_distance_sqr: float = INF
|
||||
|
||||
# Find the closest portal the ray intersects
|
||||
for portal in portals:
|
||||
@ -258,8 +258,8 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
|
||||
if portal == ignore_portal or not portal.is_inside_tree() or tree != portal.get_tree() or not portal.is_visible_in_tree():
|
||||
continue
|
||||
|
||||
var local_from:Vector3 = portal.to_local(from)
|
||||
var local_dir:Vector3 = portal.global_transform.basis.inverse() * dir
|
||||
var local_from: Vector3 = portal.to_local(from)
|
||||
var local_dir: Vector3 = portal.global_transform.basis.inverse() * dir
|
||||
|
||||
# Check if ray is parallel to the portal
|
||||
if local_dir.z == 0:
|
||||
@ -270,22 +270,22 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
|
||||
continue
|
||||
|
||||
# Get the intersection point of the ray with the Z axis
|
||||
var t:float = -local_from.z / local_dir.z
|
||||
var t: float = - local_from.z / local_dir.z
|
||||
|
||||
# Is the intersection behind the start position?
|
||||
if t < 0:
|
||||
continue
|
||||
|
||||
# Check if the ray hit inside the portal bounding box (ignoring Z)
|
||||
var local_hit:Vector3 = local_from + t * local_dir
|
||||
var aabb:AABB = portal._mesh_aabb
|
||||
if local_hit.x < aabb.position.x or local_hit.x > aabb.position.x + aabb.size.x or\
|
||||
var local_hit: Vector3 = local_from + t * local_dir
|
||||
var aabb: AABB = portal._mesh_aabb
|
||||
if local_hit.x < aabb.position.x or local_hit.x > aabb.position.x + aabb.size.x or \
|
||||
local_hit.y < aabb.position.y or local_hit.y > aabb.position.y + aabb.size.y:
|
||||
continue
|
||||
|
||||
# Check if this was the closest portal
|
||||
var hit:Vector3 = portal.to_global(local_hit)
|
||||
var distance_sqr:float = hit.distance_squared_to(from)
|
||||
var hit: Vector3 = portal.to_global(local_hit)
|
||||
var distance_sqr: float = hit.distance_squared_to(from)
|
||||
if distance_sqr < closest_distance_sqr:
|
||||
closest_hit = hit
|
||||
closest_dir = dir
|
||||
@ -293,7 +293,7 @@ static func raycast(tree:SceneTree, from:Vector3, dir:Vector3, handle_raycast:Ca
|
||||
closest_portal = portal
|
||||
|
||||
# Calculate the ray distance
|
||||
var hit_distance:float = INF if is_inf(closest_distance_sqr) else sqrt(closest_distance_sqr)
|
||||
var hit_distance: float = INF if is_inf(closest_distance_sqr) else sqrt(closest_distance_sqr)
|
||||
|
||||
# Call the user-defined raycast function
|
||||
if handle_raycast.call(from, dir, hit_distance, recursive_distance, r):
|
||||
|
@ -22,7 +22,7 @@ func _ready():
|
||||
|
||||
func _on_area_entered(area: Area3D) -> void:
|
||||
if area.has_meta("teleportable_root"):
|
||||
var root:Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
var root: Node3D = area.get_node(area.get_meta("teleportable_root"))
|
||||
print("[%f] Teleporting %s to %s" % [roundi(Time.get_ticks_msec() / 100) / 10.0, root.name, _parent_portal.exit_portal.name])
|
||||
root.global_transform = _parent_portal.real_to_exit_transform(root.global_transform)
|
||||
|
||||
|
@ -14,6 +14,7 @@ config/name="DP Konzultace"
|
||||
run/main_scene="uid://cim3ul77o0ipr"
|
||||
config/features=PackedStringArray("4.4", "Forward Plus")
|
||||
config/icon="res://icon.svg"
|
||||
config/tags=PackedStringArray("dp")
|
||||
|
||||
[display]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user