mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2025-12-15 13:00:07 +01:00
Add Split Screen Demo showing input handling (#1023)
* Add Split Screen Demo showing input handling * Style fixes, layout improvements, update to Godot 4.5 --------- Co-authored-by: Aaron Franke <arnfranke@yahoo.com>
This commit is contained in:
17
viewport/split_screen_input/README.md
Normal file
17
viewport/split_screen_input/README.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# Split Screen Input
|
||||
|
||||
A demo showing a Split Screen GUI and input handling for local multiplayer using viewports.
|
||||
|
||||
It demonstrates:
|
||||
- Single World2D, that is shared among many Viewports
|
||||
- Simplified Input Map, that uses the same Actions for all Split Screens
|
||||
- Input event routing to different viewports based on joypad device id and dedicated keyboard keys
|
||||
- Dynamic keybinding adjustment for each Split Screen
|
||||
|
||||
Language: GDScript
|
||||
|
||||
Renderer: Compatibility
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||
1
viewport/split_screen_input/icon.svg
Normal file
1
viewport/split_screen_input/icon.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg height="128" width="128" xmlns="http://www.w3.org/2000/svg"><rect x="2" y="2" width="124" height="124" rx="14" fill="#363d52" stroke="#212532" stroke-width="4"/><g transform="scale(.101) translate(122 122)"><g fill="#fff"><path d="M105 673v33q407 354 814 0v-33z"/><path fill="#478cbf" d="m105 673 152 14q12 1 15 14l4 67 132 10 8-61q2-11 15-15h162q13 4 15 15l8 61 132-10 4-67q3-13 15-14l152-14V427q30-39 56-81-35-59-83-108-43 20-82 47-40-37-88-64 7-51 8-102-59-28-123-42-26 43-46 89-49-7-98 0-20-46-46-89-64 14-123 42 1 51 8 102-48 27-88 64-39-27-82-47-48 49-83 108 26 42 56 81zm0 33v39c0 276 813 276 813 0v-39l-134 12-5 69q-2 10-14 13l-162 11q-12 0-16-11l-10-65H447l-10 65q-4 11-16 11l-162-11q-12-3-14-13l-5-69z"/><path d="M483 600c3 34 55 34 58 0v-86c-3-34-55-34-58 0z"/><circle cx="725" cy="526" r="90"/><circle cx="299" cy="526" r="90"/></g><g fill="#414042"><circle cx="307" cy="532" r="60"/><circle cx="717" cy="532" r="60"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 950 B |
43
viewport/split_screen_input/icon.svg.import
Normal file
43
viewport/split_screen_input/icon.svg.import
Normal file
@@ -0,0 +1,43 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://ci5b7o7h2bmj0"
|
||||
path="res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.svg"
|
||||
dest_files=["res://.godot/imported/icon.svg-218a8f2b3041327d8a5756f3a245f83b.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=false
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=1
|
||||
svg/scale=1.0
|
||||
editor/scale_with_editor_scale=false
|
||||
editor/convert_colors_with_editor_theme=false
|
||||
28
viewport/split_screen_input/player.gd
Normal file
28
viewport/split_screen_input/player.gd
Normal file
@@ -0,0 +1,28 @@
|
||||
class_name Player
|
||||
extends CharacterBody2D
|
||||
## Player implementation.
|
||||
|
||||
const factor: float = 200.0 # Factor to multiply the movement.
|
||||
|
||||
var _movement: Vector2 = Vector2(0, 0) # Current movement rate of node.
|
||||
|
||||
|
||||
# Update movement variable based on input that reaches this SubViewport.
|
||||
func _unhandled_input(event: InputEvent) -> void:
|
||||
if event.is_action_pressed("ux_up") or event.is_action_released("ux_down"):
|
||||
_movement.y -= 1
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ux_down") or event.is_action_released("ux_up"):
|
||||
_movement.y += 1
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ux_left") or event.is_action_released("ux_right"):
|
||||
_movement.x -= 1
|
||||
get_viewport().set_input_as_handled()
|
||||
elif event.is_action_pressed("ux_right") or event.is_action_released("ux_left"):
|
||||
_movement.x += 1
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
|
||||
# Move the node based on the content of the movement variable.
|
||||
func _physics_process(delta: float) -> void:
|
||||
move_and_collide(_movement * factor * delta)
|
||||
1
viewport/split_screen_input/player.gd.uid
Normal file
1
viewport/split_screen_input/player.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b7p2tpqjka6jq
|
||||
88
viewport/split_screen_input/project.godot
Normal file
88
viewport/split_screen_input/project.godot
Normal file
@@ -0,0 +1,88 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=5
|
||||
|
||||
[application]
|
||||
|
||||
config/name="Split Screen Input"
|
||||
config/tags=PackedStringArray("demo", "input", "official", "rendering")
|
||||
run/main_scene="res://split_screen_demo.tscn"
|
||||
config/features=PackedStringArray("4.5")
|
||||
config/icon="res://icon.svg"
|
||||
|
||||
[display]
|
||||
|
||||
window/size/viewport_width=800
|
||||
window/size/viewport_height=800
|
||||
window/stretch/mode="canvas_items"
|
||||
window/stretch/aspect="expand"
|
||||
|
||||
[input]
|
||||
|
||||
ui_left={
|
||||
"deadzone": 0.2,
|
||||
"events": []
|
||||
}
|
||||
ui_right={
|
||||
"deadzone": 0.2,
|
||||
"events": []
|
||||
}
|
||||
ui_up={
|
||||
"deadzone": 0.2,
|
||||
"events": []
|
||||
}
|
||||
ui_down={
|
||||
"deadzone": 0.2,
|
||||
"events": []
|
||||
}
|
||||
ux_left={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":-1.0,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":74,"key_label":0,"unicode":106,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194442,"key_label":0,"unicode":52,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":13,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ux_right={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":0,"axis_value":1.0,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":76,"key_label":0,"unicode":108,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194444,"key_label":0,"unicode":54,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ux_up={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":-1.0,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":73,"key_label":0,"unicode":105,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194446,"key_label":0,"unicode":56,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
ux_down={
|
||||
"deadzone": 0.2,
|
||||
"events": [Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":-1,"axis":1,"axis_value":1.0,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":75,"key_label":0,"unicode":107,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":4194443,"key_label":0,"unicode":53,"location":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[rendering]
|
||||
|
||||
renderer/rendering_method="gl_compatibility"
|
||||
renderer/rendering_method.mobile="gl_compatibility"
|
||||
46
viewport/split_screen_input/root.gd
Normal file
46
viewport/split_screen_input/root.gd
Normal file
@@ -0,0 +1,46 @@
|
||||
## Set up different Split Screens
|
||||
## Provide Input configuration
|
||||
## Connect Split Screens to Play Area
|
||||
extends Node
|
||||
|
||||
|
||||
const KEYBOARD_OPTIONS: Dictionary[String, Dictionary] = {
|
||||
"wasd": {"keys": [KEY_W, KEY_A, KEY_S, KEY_D]},
|
||||
"ijkl": {"keys": [KEY_I, KEY_J, KEY_K, KEY_L]},
|
||||
"arrows": {"keys": [KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN]},
|
||||
"numpad": {"keys": [KEY_KP_4, KEY_KP_5, KEY_KP_6, KEY_KP_8]},
|
||||
} # 4 keyboard sets for moving players around.
|
||||
|
||||
const PLAYER_COLORS: Array[Color] = [
|
||||
Color.WHITE,
|
||||
Color("ff8f02"),
|
||||
Color("05ff5a"),
|
||||
Color("ff05a0")
|
||||
] # Modulate Colors of each Player.
|
||||
|
||||
|
||||
var config: Dictionary = {
|
||||
"keyboard": KEYBOARD_OPTIONS,
|
||||
"joypads": 4,
|
||||
"world": null,
|
||||
"position": Vector2(),
|
||||
"index": -1,
|
||||
"color": Color(),
|
||||
} # Split Screen configuration Dictionary.
|
||||
|
||||
@onready var play_area: SubViewport = $PlayArea # The central Viewport, all Split Screens are sharing.
|
||||
|
||||
|
||||
# Initialize each Split Screen and each player node.
|
||||
func _ready() -> void:
|
||||
config["world"] = play_area.world_2d
|
||||
var children: Array[Node] = get_children()
|
||||
var index: int = 0
|
||||
for child: Node in children:
|
||||
if child is SplitScreen:
|
||||
config["position"] = Vector2(index % 2, floor(index / 2.0)) * 132 + Vector2(132, 0)
|
||||
config["index"] = index
|
||||
config["color"] = PLAYER_COLORS[index]
|
||||
var split_child: SplitScreen = child as SplitScreen
|
||||
split_child.set_config(config)
|
||||
index += 1
|
||||
1
viewport/split_screen_input/root.gd.uid
Normal file
1
viewport/split_screen_input/root.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bdikev0kwlu1g
|
||||
0
viewport/split_screen_input/screenshots/.gdignore
Normal file
0
viewport/split_screen_input/screenshots/.gdignore
Normal file
BIN
viewport/split_screen_input/screenshots/split_screen_input.webp
Normal file
BIN
viewport/split_screen_input/screenshots/split_screen_input.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
40
viewport/split_screen_input/split_screen.gd
Normal file
40
viewport/split_screen_input/split_screen.gd
Normal file
@@ -0,0 +1,40 @@
|
||||
## Interface for a SplitScreen
|
||||
class_name SplitScreen
|
||||
extends Node
|
||||
|
||||
|
||||
const JOYPAD_PREFIX: String = "Joypad"
|
||||
|
||||
@export var init_position := Vector2.ZERO
|
||||
|
||||
var _keyboard_options: Dictionary # Copy of all keyboard options.
|
||||
|
||||
@onready var opt: OptionButton = $OptionButton
|
||||
@onready var viewport: SubViewport = $InputRoutingViewportContainer/SubViewport
|
||||
@onready var input_router: InputRoutingViewportContainer = $InputRoutingViewportContainer
|
||||
@onready var play: Player = $InputRoutingViewportContainer/SubViewport/Player
|
||||
|
||||
|
||||
# Set the configuration of this split screen and perform OptionButton initialization.
|
||||
func set_config(config_dict: Dictionary):
|
||||
_keyboard_options = config_dict["keyboard"]
|
||||
play.position = config_dict["position"]
|
||||
var local_index: int = config_dict["index"]
|
||||
play.modulate = config_dict["color"]
|
||||
opt.clear()
|
||||
for keyboard_opt in _keyboard_options:
|
||||
opt.add_item(keyboard_opt)
|
||||
for index in config_dict["joypads"]:
|
||||
opt.add_item("%s %s" % [JOYPAD_PREFIX, index + 1])
|
||||
opt.select(local_index)
|
||||
_on_option_button_item_selected(local_index)
|
||||
viewport.world_2d = config_dict["world"] # Connect all Split Screens to the same World2D.
|
||||
|
||||
|
||||
# Update Keyboard Settings after selecting them in the OptionButton.
|
||||
func _on_option_button_item_selected(index: int) -> void:
|
||||
var text: String = opt.get_item_text(index)
|
||||
if text.begins_with(JOYPAD_PREFIX):
|
||||
input_router.set_input_config({"joypad": text.substr(text.length() - 1, -1).to_int(), "keyboard": []})
|
||||
else:
|
||||
input_router.set_input_config({"keyboard": _keyboard_options[text]["keys"], "joypad": -1})
|
||||
1
viewport/split_screen_input/split_screen.gd.uid
Normal file
1
viewport/split_screen_input/split_screen.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://crrvxnm6s4ssm
|
||||
42
viewport/split_screen_input/split_screen.tscn
Normal file
42
viewport/split_screen_input/split_screen.tscn
Normal file
@@ -0,0 +1,42 @@
|
||||
[gd_scene load_steps=6 format=3 uid="uid://dqailbm8vcpf5"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://crrvxnm6s4ssm" path="res://split_screen.gd" id="1_4fp0b"]
|
||||
[ext_resource type="Script" uid="uid://mplfqw0th285" path="res://sub_viewport_container.gd" id="2_v8t84"]
|
||||
[ext_resource type="Texture2D" uid="uid://ci5b7o7h2bmj0" path="res://icon.svg" id="4_787wn"]
|
||||
[ext_resource type="Script" uid="uid://b7p2tpqjka6jq" path="res://player.gd" id="5_1qhfw"]
|
||||
|
||||
[sub_resource type="RectangleShape2D" id="RectangleShape2D_m48mh"]
|
||||
size = Vector2(128, 128)
|
||||
|
||||
[node name="Split" type="VBoxContainer"]
|
||||
auto_translate_mode = 1
|
||||
offset_right = 350.0
|
||||
offset_bottom = 374.0
|
||||
script = ExtResource("1_4fp0b")
|
||||
|
||||
[node name="OptionButton" type="OptionButton" parent="."]
|
||||
auto_translate_mode = 1
|
||||
layout_mode = 2
|
||||
|
||||
[node name="InputRoutingViewportContainer" type="SubViewportContainer" parent="."]
|
||||
auto_translate_mode = 1
|
||||
layout_mode = 2
|
||||
script = ExtResource("2_v8t84")
|
||||
|
||||
[node name="SubViewport" type="SubViewport" parent="InputRoutingViewportContainer"]
|
||||
handle_input_locally = false
|
||||
size = Vector2i(350, 350)
|
||||
render_target_update_mode = 4
|
||||
|
||||
[node name="Player" type="CharacterBody2D" parent="InputRoutingViewportContainer/SubViewport"]
|
||||
script = ExtResource("5_1qhfw")
|
||||
|
||||
[node name="CollisionShape2D" type="CollisionShape2D" parent="InputRoutingViewportContainer/SubViewport/Player"]
|
||||
shape = SubResource("RectangleShape2D_m48mh")
|
||||
|
||||
[node name="Sprite2D" type="Sprite2D" parent="InputRoutingViewportContainer/SubViewport/Player"]
|
||||
texture = ExtResource("4_787wn")
|
||||
|
||||
[node name="Camera2D" type="Camera2D" parent="InputRoutingViewportContainer/SubViewport/Player"]
|
||||
|
||||
[connection signal="item_selected" from="OptionButton" to="." method="_on_option_button_item_selected"]
|
||||
73
viewport/split_screen_input/split_screen_demo.tscn
Normal file
73
viewport/split_screen_input/split_screen_demo.tscn
Normal file
@@ -0,0 +1,73 @@
|
||||
[gd_scene load_steps=3 format=3 uid="uid://ccutmhshaoqih"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://bdikev0kwlu1g" path="res://root.gd" id="1_2itit"]
|
||||
[ext_resource type="PackedScene" uid="uid://dqailbm8vcpf5" path="res://split_screen.tscn" id="1_mcbdt"]
|
||||
|
||||
[node name="Node" type="Node"]
|
||||
script = ExtResource("1_2itit")
|
||||
|
||||
[node name="Panel" type="Panel" parent="."]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="SplitScreen1" parent="." instance=ExtResource("1_mcbdt")]
|
||||
anchors_preset = -1
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -375.0
|
||||
offset_top = -387.0
|
||||
offset_right = -25.0
|
||||
offset_bottom = -13.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="SplitScreen2" parent="." instance=ExtResource("1_mcbdt")]
|
||||
anchors_preset = -1
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 25.0
|
||||
offset_top = -387.0
|
||||
offset_right = 375.0
|
||||
offset_bottom = -13.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
init_position = Vector2(132, 0)
|
||||
|
||||
[node name="SplitScreen3" parent="." instance=ExtResource("1_mcbdt")]
|
||||
anchors_preset = -1
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = -375.0
|
||||
offset_top = 13.0
|
||||
offset_right = -25.0
|
||||
offset_bottom = 387.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
init_position = Vector2(0, 132)
|
||||
|
||||
[node name="SplitScreen4" parent="." instance=ExtResource("1_mcbdt")]
|
||||
anchors_preset = -1
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
offset_left = 25.0
|
||||
offset_top = 13.0
|
||||
offset_right = 375.0
|
||||
offset_bottom = 387.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
init_position = Vector2(132, 132)
|
||||
|
||||
[node name="PlayArea" type="SubViewport" parent="."]
|
||||
render_target_update_mode = 4
|
||||
27
viewport/split_screen_input/sub_viewport_container.gd
Normal file
27
viewport/split_screen_input/sub_viewport_container.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
## Input Routing for different SubViewports.
|
||||
## Based on the provided input configuration, ensures only the correct
|
||||
## events reaching the SubViewport.
|
||||
class_name InputRoutingViewportContainer
|
||||
extends SubViewportContainer
|
||||
|
||||
|
||||
var _current_keyboard_set: Array = [] # Currently used keyboard set.
|
||||
var _current_joypad_device: int = -1 # Currently used joypad device id.
|
||||
|
||||
|
||||
# Make sure, that only the events are sent to the SubViewport,
|
||||
# that are allowed via the OptionButton selection.
|
||||
func _propagate_input_event(input_event: InputEvent) -> bool:
|
||||
if input_event is InputEventKey:
|
||||
if _current_keyboard_set.has(input_event.keycode):
|
||||
return true
|
||||
elif input_event is InputEventJoypadButton:
|
||||
if _current_joypad_device > -1 and input_event.device == _current_joypad_device:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
# Set new config for input handling.
|
||||
func set_input_config(config_dict: Dictionary):
|
||||
_current_keyboard_set = config_dict["keyboard"]
|
||||
_current_joypad_device = config_dict["joypad"]
|
||||
@@ -0,0 +1 @@
|
||||
uid://mplfqw0th285
|
||||
Reference in New Issue
Block a user