Skip to content

Commit

Permalink
refactor the dynamic split screen demo
Browse files Browse the repository at this point in the history
 - both 2D and 3D scenes have the exact same hierarchy
 - a single camera_controller.gd script instead of one per mode
 - the third viewport for 2D mode has been removed
  • Loading branch information
BenjaminNavarro committed Apr 14, 2024
1 parent d74395b commit c42347a
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 161 deletions.
107 changes: 0 additions & 107 deletions viewport/dynamic_split_screen/2d/camera_controller.gd

This file was deleted.

35 changes: 15 additions & 20 deletions viewport/dynamic_split_screen/2d/split_screen.tscn
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[gd_scene load_steps=7 format=2]

[ext_resource path="res://2d/camera_controller.gd" type="Script" id=1]
[ext_resource path="res://camera_controller.gd" type="Script" id=1]
[ext_resource path="res://split_screen.shader" type="Shader" id=2]
[ext_resource path="res://icon.png" type="Texture" id=3]
[ext_resource path="res://exit_to_menu.gd" type="Script" id=4]
Expand All @@ -15,44 +15,39 @@ shader_param/player2_position = null
shader_param/split_line_thickness = null
shader_param/split_line_color = null

[node name="Main" type="Node2D"]
[node name="Game" type="Node2D"]
script = ExtResource( 4 )

[node name="View" type="TextureRect" parent="."]
[node name="SplitScreen" type="Node" parent="."]
script = ExtResource( 1 )
max_separation = 100.0

[node name="View" type="TextureRect" parent="SplitScreen"]
material = SubResource( 1 )
margin_right = 1024.0
margin_bottom = 600.0
texture = ExtResource( 3 )
expand = true

[node name="Cameras" type="Node" parent="."]
script = ExtResource( 1 )
max_separation = 100.0

[node name="Viewport1" type="Viewport" parent="Cameras"]
size = Vector2( 100, 100 )
[node name="Main" type="Viewport" parent="SplitScreen"]
size = Vector2( 1024, 600 )
disable_3d = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 3

[node name="Camera" type="Camera2D" parent="Cameras/Viewport1"]
[node name="Level" parent="SplitScreen/Main" instance=ExtResource( 5 )]

[node name="Camera" type="Camera2D" parent="SplitScreen/Main"]
current = true
zoom = Vector2( 0.2, 0.2 )

[node name="Viewport2" type="Viewport" parent="Cameras"]
[node name="Secondary" type="Viewport" parent="SplitScreen"]
size = Vector2( 100, 100 )
disable_3d = true
usage = 0
render_target_v_flip = true
render_target_update_mode = 3

[node name="Camera" type="Camera2D" parent="Cameras/Viewport2"]
[node name="Camera" type="Camera2D" parent="SplitScreen/Secondary"]
current = true
zoom = Vector2( 0.2, 0.2 )

[node name="Game" type="Viewport" parent="."]
size = Vector2( 1024, 600 )
disable_3d = true
usage = 0

[node name="Level" parent="Game" instance=ExtResource( 5 )]
24 changes: 12 additions & 12 deletions viewport/dynamic_split_screen/3d/split_screen.tscn
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[gd_scene load_steps=7 format=2]

[ext_resource path="res://3d/level.tscn" type="PackedScene" id=1]
[ext_resource path="res://3d/camera_controller.gd" type="Script" id=2]
[ext_resource path="res://camera_controller.gd" type="Script" id=2]
[ext_resource path="res://split_screen.shader" type="Shader" id=3]
[ext_resource path="res://icon.png" type="Texture" id=4]
[ext_resource path="res://exit_to_menu.gd" type="Script" id=6]
Expand All @@ -15,39 +15,39 @@ shader_param/player2_position = null
shader_param/split_line_thickness = null
shader_param/split_line_color = null

[node name="Main" type="Spatial"]
[node name="Game" type="Spatial"]
script = ExtResource( 6 )

[node name="View" type="TextureRect" parent="."]
[node name="SplitScreen" type="Node" parent="."]
script = ExtResource( 2 )

[node name="View" type="TextureRect" parent="SplitScreen"]
material = SubResource( 1 )
anchor_right = 1.0
anchor_bottom = 1.0
texture = ExtResource( 4 )
expand = true

[node name="Cameras" type="Spatial" parent="."]
script = ExtResource( 2 )

[node name="Viewport1" type="Viewport" parent="Cameras"]
[node name="Main" type="Viewport" parent="SplitScreen"]
size = Vector2( 100, 100 )
msaa = 2
usage = 3
render_target_v_flip = true
render_target_update_mode = 3

[node name="Camera1" type="Camera" parent="Cameras/Viewport1"]
[node name="Level" parent="SplitScreen/Main" instance=ExtResource( 1 )]

[node name="Camera" type="Camera" parent="SplitScreen/Main"]
transform = Transform( 1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 20, 0 )
current = true

[node name="Viewport2" type="Viewport" parent="Cameras"]
[node name="Secondary" type="Viewport" parent="SplitScreen"]
size = Vector2( 100, 100 )
msaa = 2
usage = 3
render_target_v_flip = true
render_target_update_mode = 3

[node name="Camera2" type="Camera" parent="Cameras/Viewport2"]
[node name="Camera" type="Camera" parent="SplitScreen/Secondary"]
transform = Transform( 1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 20, 0 )
current = true

[node name="Level" parent="." instance=ExtResource( 1 )]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ extends Node
# SplitScreen shader to achieve the dynamic split screen effet
#
# Cameras are placed 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.
# if players are close enough or at a fixed distance from them 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 an unsplit screen.
Expand All @@ -21,28 +21,36 @@ extends Node
# split_line_thickness. If false, the thickness will be constant and equal
# to split_line_thickness.


enum Mode {
Mode2D,
Mode3D
}

export(float) var max_separation = 20.0
export(float) var split_line_thickness = 3.0
export(Color, RGBA) var split_line_color = Color.black
export(bool) var adaptive_split_line_thickness = true

onready var player1 = $"/root/Main/Level/Player1"
onready var player2 = $"/root/Main/Level/Player2"
onready var view = $"/root/Main/View"
onready var viewport1 = $Viewport1
onready var viewport2 = $Viewport2
onready var camera1 = viewport1.get_node(@"Camera1")
onready var camera2 = viewport2.get_node(@"Camera2")

onready var main_viewport = $Main
onready var secondary_viewport = $Secondary
onready var level = main_viewport.get_node(@"Level")
onready var player1 = level.get_node(@"Player1")
onready var player2 = level.get_node(@"Player2")
onready var view = $View
onready var camera1 = main_viewport.get_node(@"Camera")
onready var camera2 = secondary_viewport.get_node(@"Camera")
onready var mode = Mode.Mode2D if camera1 is Camera2D else Mode.Mode3D

func _ready():
secondary_viewport.world_2d = main_viewport.world_2d
_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())
view.material.set_shader_param("viewport1", main_viewport.get_texture())
view.material.set_shader_param("viewport2", secondary_viewport.get_texture())


func _process(_delta):
Expand All @@ -57,17 +65,30 @@ func _move_cameras():

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
match mode:
Mode.Mode2D:
camera1.position = player1.position + position_difference / 2.0
camera2.position = player2.position - position_difference / 2.0
Mode.Mode3D:
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
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) / screen_size
var player2_position = camera2.unproject_position(player2.translation) / screen_size
var player1_position
var player2_position

match mode:
Mode.Mode2D:
player1_position = (player1.position - camera1.position) / (camera1.zoom * screen_size) + Vector2(0.5, 0.5)
player2_position = (player2.position - camera2.position) / (camera2.zoom * screen_size) + Vector2(0.5, 0.5)
Mode.Mode3D:
player1_position = camera1.unproject_position(player1.translation) / screen_size
player2_position = camera2.unproject_position(player2.translation) / screen_size

var thickness
if adaptive_split_line_thickness:
Expand All @@ -87,7 +108,7 @@ func _update_splitscreen():


# Split screen is active if players are too far apart from each other.
# Only the horizontal components (x, z) are used for distance computation
# Only the horizontal components (x/z in 3D, x/y in 2D) 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)
Expand All @@ -97,15 +118,15 @@ func _get_split_state():
func _on_size_changed():
var screen_size = get_viewport().get_visible_rect().size

$Viewport1.size = screen_size
$Viewport2.size = screen_size
main_viewport.size = screen_size
secondary_viewport.size = screen_size

view.material.set_shader_param("viewport_size", screen_size)


func _compute_position_difference_in_world():
return player2.translation - player1.translation
return player2.position - player1.position if mode == Mode.Mode2D else player2.translation - player1.translation


func _compute_horizontal_length(vec):
return Vector2(vec.x, vec.z).length()
return Vector2(vec.x, vec.y).length() if mode == Mode.Mode2D else Vector2(vec.x, vec.z).length()

0 comments on commit c42347a

Please sign in to comment.