[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
This commit is contained in:
Benjamin Navarro
2025-10-03 02:03:12 +02:00
committed by GitHub
parent ec368a812b
commit fe1ccaea77
22 changed files with 892 additions and 96 deletions

View File

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

View File

@@ -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 )

View File

@@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -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

View File

@@ -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 )

Binary file not shown.

After

Width:  |  Height:  |  Size: 502 B

View File

@@ -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

View File

@@ -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())

View File

@@ -1,19 +1,7 @@
[gd_scene load_steps=58 format=2]
[gd_scene load_steps=54 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
[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]
@@ -164,54 +152,19 @@ albedo_color = Color( 0.770645, 0.287346, 0.739309, 1 )
[sub_resource type="SpatialMaterial" id=52]
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="."]
environment = ExtResource( 1 )
environment = ExtResource( 2 )
[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 )
shadow_enabled = true
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="."]
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"]
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="."]
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
[node name="Mesh" type="MeshInstance" parent="Player2"]

View File

@@ -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

View File

@@ -1,26 +1,25 @@
# Dynamic Split Screen
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
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
## Details
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'
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
@@ -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
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.
The cameras are placed on the segment joining the two players,
@@ -38,14 +37,26 @@ distance otherwise.
## 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
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/splitscreen.png)
### 2D
![Screenshots](screenshots/splitscreen_2d.png)
### 3D
![Screenshots](screenshots/splitscreen_3d.png)

View File

@@ -1,47 +1,56 @@
extends Spatial
extends Node
# Handle the motion of both player cameras 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.
# 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
# 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
# segement joining the two players.
# segment 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
# 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 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 = $"../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 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():
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):
@@ -56,6 +65,11 @@ func _move_cameras():
position_difference = position_difference.normalized() * distance
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
@@ -65,15 +79,24 @@ func _move_cameras():
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:
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)
if thickness > 0:
thickness = clamp(thickness, 1, split_line_thickness)
else:
thickness = split_line_thickness
@@ -85,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)
@@ -95,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()

View File

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

View File

@@ -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")

View File

@@ -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"]

Binary file not shown.

View File

@@ -13,7 +13,7 @@ config_version=4
config/name="Dynamic Split Screen"
config/description="This sample project showcases an implementation of dynamic
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"
[debug]

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB