Files
godot-demo-projects/viewport/dynamic_split_screen/CameraController.gd
Benjamin Navarro f922bcb8c7 Add dynamic split screen demo
Answering PR reviews

Removeing class_name

_get_split_state documentation

Mentioning Voronoi split screen in README

Fixing comments

Use the same script for both players

The input map is configured to work with AZERTY and QWERTY keyboards

Use spaces for comments alignment + code style

Fix empty line and incorrect comment

Add arrow keys to control player 2

Removing most static typing as suggested for demo projects

Removing broken split origin feature

Removing the floor texture to avoid copyright issues

Changing game icon

Make Walls.gd a tool script + randomize

Fixing style

 Handle joysticks for player movement
2020-01-27 08:58:50 +01:00

114 lines
4.2 KiB
GDScript

extends Spatial
# Handle the motion of both players' camera as well as communication with the
# SplitScreen shader to achieve the dynamic split screen effet
#
# Cameras are place on the segment joining the two players, either in the middle
# if players are close enough or at a fixed distance if they are not.
# In the first case, both cameras being at the same location, only the view of
# the first one is used for the entire screen thus allowing the players to play
# on a unsplit screen.
# In the second case, the screen is split in two with a line perpendicular to the
# segement joining the two players.
#
# The points of customization are:
# max_separation: the distance between players at which the view starts to split
# split_line_thickness: the thickness of the split line in pixels
# split_line_color: color of the split line
# adaptive_split_line_thickness: if true, the split line thickness will vary
# depending on the distance between players. If false, the thickness will
# be constant and equal to split_line_thickness
export(float) var max_separation = 20.0
export(float) var split_line_thickness = 3.0
export(Color, RGBA) var split_line_color = Color(0.0, 0.0, 0.0, 1.0)
export(bool) var adaptive_split_line_thickness = true
onready var player1 = $'../Player1'
onready var player2 = $'../Player2'
onready var camera1: Camera = $'Viewport1/Camera1'
onready var camera2: Camera = $'Viewport2/Camera2'
onready var view: TextureRect = $'View'
func _ready():
_on_size_changed()
_update_splitscreen()
get_viewport().connect("size_changed", self, "_on_size_changed")
view.material.set_shader_param('viewport1', $Viewport1.get_texture())
view.material.set_shader_param('viewport2', $Viewport2.get_texture())
func _process(delta):
_move_cameras()
_update_splitscreen()
func _move_cameras():
var position_difference = _compute_position_difference_in_world()
var distance = clamp(_compute_horizontal_length(position_difference), 0, max_separation)
position_difference = position_difference.normalized() * distance
camera1.translation.x = player1.translation.x + position_difference.x / 2.0
camera1.translation.z = player1.translation.z + position_difference.z / 2.0
camera2.translation.x = player2.translation.x - position_difference.x / 2.0
camera2.translation.z = player2.translation.z - position_difference.z / 2.0
func _update_splitscreen():
var screen_size = get_viewport().get_visible_rect().size
var player1_position = camera1.unproject_position(player1.translation)
player1_position.x /= screen_size.x;
player1_position.y /= screen_size.y;
var player2_position = camera2.unproject_position(player2.translation)
player2_position.x /= screen_size.x;
player2_position.y /= screen_size.y;
var thickness
if adaptive_split_line_thickness:
var position_difference = _compute_position_difference_in_world()
var distance = _compute_horizontal_length(position_difference)
thickness = lerp(0, split_line_thickness, (distance - max_separation) / max_separation)
thickness = clamp(thickness, 0, split_line_thickness)
else:
thickness = split_line_thickness
view.material.set_shader_param('split_active', _get_split_state())
view.material.set_shader_param('player1_position', player1_position)
view.material.set_shader_param('player2_position', player2_position)
view.material.set_shader_param('split_line_thickness', thickness)
view.material.set_shader_param('split_line_color', split_line_color)
# Split screen is active if players are too far apart from each other.
# Only the horizontal components (x, z) are used for distance computation
func _get_split_state():
var position_difference = _compute_position_difference_in_world()
var separation_distance = _compute_horizontal_length(position_difference)
return separation_distance > max_separation
func _on_size_changed():
var screen_size = get_viewport().get_visible_rect().size
$Viewport1.size = screen_size
$Viewport2.size = screen_size
view.rect_size = screen_size
view.material.set_shader_param('viewport_size', screen_size)
func _compute_position_difference_in_world():
return player2.translation - player1.translation
func _compute_horizontal_length(vec):
return Vector2(vec.x, vec.z).length()