Browse Source

[3.x] Add a 2D version of the dynamic split screen demo (#762)

* add a 2D version of the dynamic split screen demo

* refactor the dynamic split screen demo

 - 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
Benjamin Navarro 1 week ago
parent
commit
fe1ccaea77

+ 1 - 0
viewport/dynamic_split_screen/.gitignore

@@ -0,0 +1 @@
+export/

+ 531 - 0
viewport/dynamic_split_screen/2d/level.tscn

@@ -0,0 +1,531 @@
+[gd_scene load_steps=8 format=2]
+
+[ext_resource path="res://2d/player.gd" type="Script" id=1]
+[ext_resource path="res://2d/wall_coloring.gd" type="Script" id=2]
+[ext_resource path="res://2d/square.png" type="Texture" id=3]
+[ext_resource path="res://2d/player.png" type="Texture" id=4]
+
+[sub_resource type="CircleShape2D" id=3]
+radius = 8.0
+
+[sub_resource type="CircleShape2D" id=4]
+radius = 8.06226
+
+[sub_resource type="RectangleShape2D" id=2]
+extents = Vector2( 8, 8 )
+
+[node name="Level" type="Node2D"]
+
+[node name="Player1" type="KinematicBody2D" parent="."]
+position = Vector2( -36, -16 )
+script = ExtResource( 1 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player1"]
+shape = SubResource( 3 )
+
+[node name="Sprite" type="Sprite" parent="Player1"]
+modulate = Color( 1, 0, 0, 1 )
+scale = Vector2( 0.25, 0.25 )
+texture = ExtResource( 4 )
+
+[node name="Player2" type="KinematicBody2D" parent="."]
+position = Vector2( 25, 42 )
+script = ExtResource( 1 )
+player_id = 2
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Player2"]
+shape = SubResource( 4 )
+
+[node name="Sprite" type="Sprite" parent="Player2"]
+modulate = Color( 0, 0.588235, 1, 1 )
+scale = Vector2( 0.25, 0.25 )
+texture = ExtResource( 4 )
+
+[node name="Walls" type="Node2D" parent="."]
+script = ExtResource( 2 )
+
+[node name="Group1" type="Node2D" parent="Walls"]
+position = Vector2( 342, -1.00002 )
+rotation = 0.707648
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group1"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group1/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group1/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.607891, 0.046592, 0.00570985, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group1"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group1/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group1/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.404256, 0.898451, 0.937987, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group1"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group1/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group1/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.180765, 0.0852998, 0.0428303, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group1"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group1/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group1/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.0991764, 0.976524, 0.341112, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group8" type="Node2D" parent="Walls"]
+position = Vector2( -119, -69 )
+rotation = 0.707648
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group8"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group8/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group8/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.607891, 0.046592, 0.00570985, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group8"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group8/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group8/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.404256, 0.898451, 0.937987, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group8"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group8/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group8/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.180765, 0.0852998, 0.0428303, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group8"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group8/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group8/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.0991764, 0.976524, 0.341112, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group6" type="Node2D" parent="Walls"]
+position = Vector2( -12, -162 )
+rotation = -0.472087
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group6"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group6/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group6/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.830074, 0.71524, 0.115105, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group6"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group6/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group6/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.86402, 0.891686, 0.747119, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group6"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group6/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group6/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.176854, 0.187306, 0.991179, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group6"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group6/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group6/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.909202, 0.190021, 0.310404, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group9" type="Node2D" parent="Walls"]
+position = Vector2( 7, 268 )
+rotation = 1.44794
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group9"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group9/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group9/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.830074, 0.71524, 0.115105, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group9"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group9/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group9/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.86402, 0.891686, 0.747119, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group9"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group9/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group9/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.176854, 0.187306, 0.991179, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group9"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group9/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group9/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.909202, 0.190021, 0.310404, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group2" type="Node2D" parent="Walls"]
+position = Vector2( 166, 1 )
+rotation = -2.65517
+scale = Vector2( 0.5, 0.5 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group2"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group2/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group2/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.255383, 0.0261656, 0.866709, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group2"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group2/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group2/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.484218, 0.0260328, 0.657083, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group2"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group2/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group2/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.20515, 0.697483, 0.160248, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group2"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group2/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group2/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.641967, 0.583661, 0.16892, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group5" type="Node2D" parent="Walls"]
+position = Vector2( -31, 77 )
+rotation = -1.82393
+scale = Vector2( 0.5, 0.5 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group5"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group5/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group5/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.394341, 0.0701354, 0.101846, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group5"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group5/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group5/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.94116, 0.566994, 0.606703, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group5"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group5/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group5/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.276915, 0.426239, 0.60367, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group5"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group5/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group5/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.673828, 0.857139, 0.0330471, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group10" type="Node2D" parent="Walls"]
+position = Vector2( -215, 133 )
+rotation = -2.80987
+scale = Vector2( 0.5, 0.5 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group10"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group10/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group10/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.394341, 0.0701354, 0.101846, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group10"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group10/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group10/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.94116, 0.566994, 0.606703, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group10"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group10/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group10/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.276915, 0.426239, 0.60367, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group10"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group10/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group10/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.673828, 0.857139, 0.0330471, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group4" type="Node2D" parent="Walls"]
+position = Vector2( 162, 197 )
+rotation = -0.800594
+scale = Vector2( 0.5, 0.5 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group4"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group4/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group4/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.334467, 0.798133, 0.45167, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group4"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group4/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group4/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.386136, 0.875769, 0.0833352, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group4"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group4/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group4/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.680544, 0.336621, 0.477674, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group4"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group4/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group4/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.810584, 0.863357, 0.582931, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group3" type="Node2D" parent="Walls"]
+position = Vector2( 142, 27 )
+rotation = 1.61359
+scale = Vector2( 2, 2 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group3"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group3/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group3/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.0134517, 0.400895, 0.508833, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group3"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group3/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group3/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.280046, 0.408967, 0.911763, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group3"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group3/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group3/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.228981, 0.571434, 0.607728, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group3"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group3/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group3/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.398647, 0.433863, 0.423729, 1 )
+texture = ExtResource( 3 )
+
+[node name="Group7" type="Node2D" parent="Walls"]
+position = Vector2( -228, 127 )
+rotation = 3.15427
+scale = Vector2( 2, 2 )
+
+[node name="StaticBody2D" type="StaticBody2D" parent="Walls/Group7"]
+position = Vector2( -68, -17 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group7/StaticBody2D"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group7/StaticBody2D" groups=["walls"]]
+modulate = Color( 0.0134517, 0.400895, 0.508833, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D4" type="StaticBody2D" parent="Walls/Group7"]
+position = Vector2( 52, 29 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group7/StaticBody2D4"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group7/StaticBody2D4" groups=["walls"]]
+modulate = Color( 0.280046, 0.408967, 0.911763, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D2" type="StaticBody2D" parent="Walls/Group7"]
+position = Vector2( -20, 48 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group7/StaticBody2D2"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group7/StaticBody2D2" groups=["walls"]]
+modulate = Color( 0.228981, 0.571434, 0.607728, 1 )
+texture = ExtResource( 3 )
+
+[node name="StaticBody2D3" type="StaticBody2D" parent="Walls/Group7"]
+position = Vector2( 35, -38 )
+scale = Vector2( 2, 2 )
+
+[node name="CollisionShape2D" type="CollisionShape2D" parent="Walls/Group7/StaticBody2D3"]
+shape = SubResource( 2 )
+
+[node name="Sprite" type="Sprite" parent="Walls/Group7/StaticBody2D3" groups=["walls"]]
+modulate = Color( 0.398647, 0.433863, 0.423729, 1 )
+texture = ExtResource( 3 )

+ 17 - 0
viewport/dynamic_split_screen/2d/player.gd

@@ -0,0 +1,17 @@
+extends KinematicBody2D
+
+
+# Moves the player
+
+export(int, 1, 2) var player_id = 1
+export(float) var walk_speed = 200.0
+
+
+func _physics_process(_delta):
+	var velocity = Vector2.ZERO
+	velocity.y = -Input.get_action_strength("move_up_player" + str(player_id))
+	velocity.y += Input.get_action_strength("move_down_player" + str(player_id))
+	velocity.x = -Input.get_action_strength("move_left_player" + str(player_id))
+	velocity.x += Input.get_action_strength("move_right_player" + str(player_id))
+
+	move_and_slide(velocity.normalized() * walk_speed)

BIN
viewport/dynamic_split_screen/2d/player.png


+ 35 - 0
viewport/dynamic_split_screen/2d/player.png.import

@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/player.png-efb1916a0d650384deb4448ddc0269fa.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://2d/player.png"
+dest_files=[ "res://.import/player.png-efb1916a0d650384deb4448ddc0269fa.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0

+ 56 - 0
viewport/dynamic_split_screen/2d/split_screen.tscn

@@ -0,0 +1,56 @@
+[gd_scene load_steps=7 format=2]
+
+[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]
+[ext_resource path="res://2d/level.tscn" type="PackedScene" id=5]
+
+[sub_resource type="ShaderMaterial" id=1]
+shader = ExtResource( 2 )
+shader_param/viewport_size = null
+shader_param/split_active = null
+shader_param/player1_position = null
+shader_param/player2_position = null
+shader_param/split_line_thickness = null
+shader_param/split_line_color = null
+
+[node name="Game" type="Node2D"]
+script = ExtResource( 4 )
+
+[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="Main" type="Viewport" parent="SplitScreen"]
+size = Vector2( 1024, 600 )
+hdr = false
+disable_3d = true
+usage = 0
+render_target_v_flip = true
+render_target_update_mode = 3
+
+[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="Secondary" type="Viewport" parent="SplitScreen"]
+size = Vector2( 100, 100 )
+hdr = false
+disable_3d = true
+usage = 0
+render_target_v_flip = true
+render_target_update_mode = 3
+
+[node name="Camera" type="Camera2D" parent="SplitScreen/Secondary"]
+current = true
+zoom = Vector2( 0.2, 0.2 )

BIN
viewport/dynamic_split_screen/2d/square.png


+ 35 - 0
viewport/dynamic_split_screen/2d/square.png.import

@@ -0,0 +1,35 @@
+[remap]
+
+importer="texture"
+type="StreamTexture"
+path="res://.import/square.png-78c70671391f71adc77019bdb5e7a73b.stex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://2d/square.png"
+dest_files=[ "res://.import/square.png-78c70671391f71adc77019bdb5e7a73b.stex" ]
+
+[params]
+
+compress/mode=0
+compress/lossy_quality=0.7
+compress/hdr_mode=0
+compress/bptc_ldr=0
+compress/normal_map=0
+flags/repeat=0
+flags/filter=true
+flags/mipmaps=false
+flags/anisotropic=false
+flags/srgb=2
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/HDR_as_SRGB=false
+process/invert_color=false
+process/normal_map_invert_y=false
+stream=false
+size_limit=0
+detect_3d=true
+svg/scale=1.0

+ 11 - 0
viewport/dynamic_split_screen/2d/wall_coloring.gd

@@ -0,0 +1,11 @@
+tool
+extends Node2D
+
+# Set a random color to all objects in the "walls" group.
+# To use, attach this script to the "Walls" node.
+
+func _ready():
+	randomize()
+	var walls = get_tree().get_nodes_in_group("walls")
+	for wall in walls:
+		wall.modulate = Color(randf(), randf(), randf())

+ 8 - 55
viewport/dynamic_split_screen/split_screen.tscn → viewport/dynamic_split_screen/3d/level.tscn

@@ -1,19 +1,7 @@
-[gd_scene load_steps=58 format=2]
-
-[ext_resource path="res://default_env.tres" type="Environment" id=1]
-[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://player.gd" type="Script" id=5]
-
-[sub_resource type="ShaderMaterial" id=1]
-shader = ExtResource( 3 )
-shader_param/viewport_size = null
-shader_param/split_active = null
-shader_param/player1_position = null
-shader_param/player2_position = null
-shader_param/split_line_thickness = null
-shader_param/split_line_color = null
+[gd_scene load_steps=54 format=2]
+
+[ext_resource path="res://3d/player.gd" type="Script" id=1]
+[ext_resource path="res://default_env.tres" type="Environment" id=2]
 
 
 [sub_resource type="CapsuleMesh" id=2]
 [sub_resource type="CapsuleMesh" id=2]
 
 
@@ -164,54 +152,19 @@ albedo_color = Color( 0.770645, 0.287346, 0.739309, 1 )
 [sub_resource type="SpatialMaterial" id=52]
 [sub_resource type="SpatialMaterial" id=52]
 albedo_color = Color( 0.791675, 0.946163, 0.317723, 1 )
 albedo_color = Color( 0.791675, 0.946163, 0.317723, 1 )
 
 
-[node name="World" type="Spatial"]
+[node name="Level" type="Spatial"]
 
 
 [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
 [node name="WorldEnvironment" type="WorldEnvironment" parent="."]
-environment = ExtResource( 1 )
+environment = ExtResource( 2 )
 
 
 [node name="DirectionalLight" type="DirectionalLight" parent="WorldEnvironment"]
 [node name="DirectionalLight" type="DirectionalLight" parent="WorldEnvironment"]
 transform = Transform( 1, 0, 0, 0, -0.818651, 0.574291, 0, -0.574291, -0.818651, 0, 70.567, -72.3668 )
 transform = Transform( 1, 0, 0, 0, -0.818651, 0.574291, 0, -0.574291, -0.818651, 0, 70.567, -72.3668 )
 shadow_enabled = true
 shadow_enabled = true
 shadow_color = Color( 0.6, 0.6, 0.6, 1 )
 shadow_color = Color( 0.6, 0.6, 0.6, 1 )
 
 
-[node name="Cameras" type="Spatial" parent="."]
-script = ExtResource( 2 )
-
-[node name="View" type="TextureRect" parent="Cameras"]
-material = SubResource( 1 )
-anchor_right = 1.0
-anchor_bottom = 1.0
-texture = ExtResource( 4 )
-expand = true
-__meta__ = {
-"_edit_use_anchors_": false
-}
-
-[node name="Viewport1" type="Viewport" parent="Cameras"]
-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"]
-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"]
-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"]
-transform = Transform( 1, 0, 0, 0, -4.37114e-08, 1, 0, -1, -4.37114e-08, 0, 20, 0 )
-current = true
-
 [node name="Player1" type="KinematicBody" parent="."]
 [node name="Player1" type="KinematicBody" parent="."]
 transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0 )
 transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.25, 0 )
-script = ExtResource( 5 )
+script = ExtResource( 1 )
 
 
 [node name="Mesh" type="MeshInstance" parent="Player1"]
 [node name="Mesh" type="MeshInstance" parent="Player1"]
 transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0 )
 transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0 )
@@ -224,7 +177,7 @@ shape = SubResource( 4 )
 
 
 [node name="Player2" type="KinematicBody" parent="."]
 [node name="Player2" type="KinematicBody" parent="."]
 transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 4.18358, 1.25, 3.01882 )
 transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 4.18358, 1.25, 3.01882 )
-script = ExtResource( 5 )
+script = ExtResource( 1 )
 player_id = 2
 player_id = 2
 
 
 [node name="Mesh" type="MeshInstance" parent="Player2"]
 [node name="Mesh" type="MeshInstance" parent="Player2"]

+ 1 - 1
viewport/dynamic_split_screen/player.gd → viewport/dynamic_split_screen/3d/player.gd

@@ -12,6 +12,6 @@ func _physics_process(_delta):
 	velocity.z = -Input.get_action_strength("move_up_player" + str(player_id))
 	velocity.z = -Input.get_action_strength("move_up_player" + str(player_id))
 	velocity.z += Input.get_action_strength("move_down_player" + str(player_id))
 	velocity.z += Input.get_action_strength("move_down_player" + str(player_id))
 	velocity.x = -Input.get_action_strength("move_left_player" + str(player_id))
 	velocity.x = -Input.get_action_strength("move_left_player" + str(player_id))
-	velocity.x +=  Input.get_action_strength("move_right_player" + str(player_id))
+	velocity.x += Input.get_action_strength("move_right_player" + str(player_id))
 
 
 	move_and_slide(velocity.normalized() * walk_speed)
 	move_and_slide(velocity.normalized() * walk_speed)

+ 53 - 0
viewport/dynamic_split_screen/3d/split_screen.tscn

@@ -0,0 +1,53 @@
+[gd_scene load_steps=7 format=2]
+
+[ext_resource path="res://3d/level.tscn" type="PackedScene" id=1]
+[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]
+
+[sub_resource type="ShaderMaterial" id=1]
+shader = ExtResource( 3 )
+shader_param/viewport_size = null
+shader_param/split_active = null
+shader_param/player1_position = null
+shader_param/player2_position = null
+shader_param/split_line_thickness = null
+shader_param/split_line_color = null
+
+[node name="Game" type="Spatial"]
+script = ExtResource( 6 )
+
+[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="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="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="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="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

+ 0 - 0
viewport/dynamic_split_screen/wall_coloring.gd → viewport/dynamic_split_screen/3d/wall_coloring.gd


+ 23 - 12
viewport/dynamic_split_screen/README.md

@@ -1,26 +1,25 @@
 # Dynamic Split Screen
 # Dynamic Split Screen
 
 
 This sample project showcases an implementation of dynamic
 This sample project showcases an implementation of dynamic
-split screen, also called Voronoi split screen.
+split screen, also called Voronoi split screen, for both 2D and 3D games.
 
 
 Language: [GDSL](https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/shading_language.html) and GDScript
 Language: [GDSL](https://docs.godotengine.org/en/latest/tutorials/shaders/shader_reference/shading_language.html) and GDScript
 
 
 Renderer: GLES 2
 Renderer: GLES 2
 
 
-Note: An HTML5 export is testable
-[here](https://benjaminnavarro.github.io/godot_dynamic_split_screen/index.html).
+Note: An HTML5 export is testable on [itch.io](https://benjaminnavarro.itch.io/godot-dynamic-split-screen-demo).
 
 
 Check out this demo on the asset library: https://godotengine.org/asset-library/asset/541
 Check out this demo on the asset library: https://godotengine.org/asset-library/asset/541
 
 
 ## Details
 ## Details
 
 
 A dynamic split screen system displays a single screen when
 A dynamic split screen system displays a single screen when
-the two players are close but a splitted view when they move apart.
+the two players are close but a split view when they move apart.
 
 
 The splitting line can take any angle depending on the players'
 The splitting line can take any angle depending on the players'
 position, so it won't be either vertical or horizontal.
 position, so it won't be either vertical or horizontal.
 
 
-This system was popularized by the Lego videogames.
+This system was popularized by the Lego video games.
 
 
 ## How it works
 ## How it works
 
 
@@ -28,8 +27,8 @@ Two cameras are placed inside two separate viewports and their
 texture, as well as some other parameters, are passed to a
 texture, as well as some other parameters, are passed to a
 shader attached to a TextureRect filling the whole screen.
 shader attached to a TextureRect filling the whole screen.
 
 
-The `SplitScreen` shader, with the help of the `CameraController`
-script, chooses wich texture to display on each pixel to
+The `split_screen` shader, with the help of the `camera_controller`
+script, chooses which texture to display on each pixel to
 achieve the effect.
 achieve the effect.
 
 
 The cameras are placed on the segment joining the two players,
 The cameras are placed on the segment joining the two players,
@@ -38,14 +37,26 @@ distance otherwise.
 
 
 ## How to use it
 ## How to use it
 
 
-Open and launch the project inside the Godot engine and then
-you can use WASD keys to move the first player and IJKL keys
-to move the second one.
+Open and launch the project inside the Godot engine, select either the
+2D or the 3D demo from the menu and then use WASD/ZQSD keys
+to move the first player and IJKL/arrows keys to move the
+second one.
+
+While a demo is running, you can press the escape key to get back
+to the menu.
 
 
 The `Cameras` node has parameters to tune the distance at
 The `Cameras` node has parameters to tune the distance at
 which the screen splits and also the width and color of
 which the screen splits and also the width and color of
-the splitting line.
+the splitting line. The `Adaptive Split Line Thickness` parameter
+select whether the split line has a constant thickness or a dynamic
+one varying depending on the distance between the two players.
 
 
 ## Screenshots
 ## Screenshots
 
 
-![Screenshots](screenshots/splitscreen.png)
+### 2D
+
+![Screenshots](screenshots/splitscreen_2d.png)
+
+### 3D
+
+![Screenshots](screenshots/splitscreen_3d.png)

+ 51 - 28
viewport/dynamic_split_screen/camera_controller.gd

@@ -1,47 +1,56 @@
-extends Spatial
+extends Node
 
 
 
 
 # Handle the motion of both player cameras as well as communication with the
 # Handle the motion of both player cameras as well as communication with the
 # SplitScreen shader to achieve the dynamic split screen effet
 # 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.
+# Cameras are placed on the segment joining the two players, either in the middle
+# 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
 # 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
 # the first one is used for the entire screen thus allowing the players to play
-# on a unsplit screen.
+# on an unsplit screen.
 # In the second case, the screen is split in two with a line perpendicular to the
 # In the second case, the screen is split in two with a line perpendicular to the
-# segement joining the two players.
+# segment joining the two players.
 #
 #
 # The points of customization are:
 # The points of customization are:
 #   max_separation: the distance between players at which the view starts to split
 #   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_thickness: the thickness of the split line in pixels
 #   split_line_color: color of the split line
 #   split_line_color: color of the split line
 #   adaptive_split_line_thickness: if true, the split line thickness will vary
 #   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
+#       depending on the distance between players, with a maximum of
+#       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 max_separation = 20.0
 export(float) var split_line_thickness = 3.0
 export(float) var split_line_thickness = 3.0
 export(Color, RGBA) var split_line_color = Color.black
 export(Color, RGBA) var split_line_color = Color.black
 export(bool) var adaptive_split_line_thickness = true
 export(bool) var adaptive_split_line_thickness = true
 
 
-onready var player1 = $"../Player1"
-onready var player2 = $"../Player2"
+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 view = $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 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():
 func _ready():
+	secondary_viewport.world_2d = main_viewport.world_2d
 	_on_size_changed()
 	_on_size_changed()
 	_update_splitscreen()
 	_update_splitscreen()
 
 
 	get_viewport().connect("size_changed", self, "_on_size_changed")
 	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):
 func _process(_delta):
@@ -56,24 +65,38 @@ func _move_cameras():
 
 
 	position_difference = position_difference.normalized() * distance
 	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():
 func _update_splitscreen():
 	var screen_size = get_viewport().get_visible_rect().size
 	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
 	var thickness
 	if adaptive_split_line_thickness:
 	if adaptive_split_line_thickness:
 		var position_difference = _compute_position_difference_in_world()
 		var position_difference = _compute_position_difference_in_world()
 		var distance = _compute_horizontal_length(position_difference)
 		var distance = _compute_horizontal_length(position_difference)
 		thickness = lerp(0, split_line_thickness, (distance - max_separation) / max_separation)
 		thickness = lerp(0, split_line_thickness, (distance - max_separation) / max_separation)
-		thickness = clamp(thickness, 0, split_line_thickness)
+		if thickness > 0:
+			thickness = clamp(thickness, 1, split_line_thickness)
 	else:
 	else:
 		thickness = split_line_thickness
 		thickness = split_line_thickness
 
 
@@ -85,7 +108,7 @@ func _update_splitscreen():
 
 
 
 
 # Split screen is active if players are too far apart from each other.
 # 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():
 func _get_split_state():
 	var position_difference = _compute_position_difference_in_world()
 	var position_difference = _compute_position_difference_in_world()
 	var separation_distance = _compute_horizontal_length(position_difference)
 	var separation_distance = _compute_horizontal_length(position_difference)
@@ -95,15 +118,15 @@ func _get_split_state():
 func _on_size_changed():
 func _on_size_changed():
 	var screen_size = get_viewport().get_visible_rect().size
 	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)
 	view.material.set_shader_param("viewport_size", screen_size)
 
 
 
 
 func _compute_position_difference_in_world():
 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):
 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()

+ 6 - 0
viewport/dynamic_split_screen/exit_to_menu.gd

@@ -0,0 +1,6 @@
+extends Node
+
+
+func _process(_delta):
+	if Input.is_action_just_pressed("ui_cancel"):
+		get_tree().change_scene("res://menu.tscn")

+ 8 - 0
viewport/dynamic_split_screen/menu.gd

@@ -0,0 +1,8 @@
+extends Control
+
+func _load_2d_demo():
+	get_tree().change_scene("res://2d/split_screen.tscn")
+
+
+func _load_3d_demo():
+	get_tree().change_scene("res://3d/split_screen.tscn")

+ 56 - 0
viewport/dynamic_split_screen/menu.tscn

@@ -0,0 +1,56 @@
+[gd_scene load_steps=5 format=2]
+
+[ext_resource path="res://noto_sans_ui_regular.ttf" type="DynamicFontData" id=1]
+[ext_resource path="res://menu.gd" type="Script" id=2]
+
+[sub_resource type="DynamicFont" id=1]
+size = 45
+font_data = ExtResource( 1 )
+
+[sub_resource type="Theme" id=2]
+default_font = SubResource( 1 )
+
+[node name="Menu" type="Control"]
+anchor_right = 1.0
+anchor_bottom = 1.0
+rect_rotation = -0.0105554
+theme = SubResource( 2 )
+script = ExtResource( 2 )
+
+[node name="CenterContainer" type="CenterContainer" parent="."]
+anchor_right = 1.0
+anchor_bottom = 1.0
+
+[node name="VBoxContainer" type="VBoxContainer" parent="CenterContainer"]
+margin_left = 112.0
+margin_top = 152.0
+margin_right = 912.0
+margin_bottom = 448.0
+
+[node name="Label" type="Label" parent="CenterContainer/VBoxContainer"]
+margin_right = 800.0
+margin_bottom = 150.0
+rect_min_size = Vector2( 800, 150 )
+custom_colors/font_color = Color( 0.290196, 0.290196, 0.290196, 1 )
+text = "Dynamic Split Screen"
+align = 1
+valign = 1
+
+[node name="StartButtons" type="VBoxContainer" parent="CenterContainer/VBoxContainer"]
+margin_top = 154.0
+margin_right = 800.0
+margin_bottom = 296.0
+
+[node name="Start2D" type="Button" parent="CenterContainer/VBoxContainer/StartButtons"]
+margin_right = 800.0
+margin_bottom = 69.0
+text = "Start 2D demo"
+
+[node name="Start3D" type="Button" parent="CenterContainer/VBoxContainer/StartButtons"]
+margin_top = 73.0
+margin_right = 800.0
+margin_bottom = 142.0
+text = "Start 3D demo"
+
+[connection signal="pressed" from="CenterContainer/VBoxContainer/StartButtons/Start2D" to="." method="_load_2d_demo"]
+[connection signal="pressed" from="CenterContainer/VBoxContainer/StartButtons/Start3D" to="." method="_load_3d_demo"]

BIN
viewport/dynamic_split_screen/noto_sans_ui_regular.ttf


+ 1 - 1
viewport/dynamic_split_screen/project.godot

@@ -13,7 +13,7 @@ config_version=4
 config/name="Dynamic Split Screen"
 config/name="Dynamic Split Screen"
 config/description="This sample project showcases an implementation of dynamic
 config/description="This sample project showcases an implementation of dynamic
 split screen, also called Voronoi split screen, using GDSL."
 split screen, also called Voronoi split screen, using GDSL."
-run/main_scene="res://split_screen.tscn"
+run/main_scene="res://menu.tscn"
 config/icon="res://icon.png"
 config/icon="res://icon.png"
 
 
 [debug]
 [debug]

BIN
viewport/dynamic_split_screen/screenshots/splitscreen_2d.png


+ 0 - 0
viewport/dynamic_split_screen/screenshots/splitscreen.png → viewport/dynamic_split_screen/screenshots/splitscreen_3d.png