mirror of
https://github.com/godotengine/godot-demo-projects.git
synced 2026-01-04 06:09:46 +03:00
[2D Platformer] Add a splitscreen mode
This commit is contained in:
@@ -148,6 +148,66 @@ toggle_pause={
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
jump_p1={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":87,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_left_p1={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":65,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":14,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
move_right_p1={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":68,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":15,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
shoot_p1={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":90,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
jump_p2={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777232,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":1,"button_index":0,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
move_left_p2={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777231,"unicode":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)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":0,"axis_value":-1.0,"script":null)
|
||||
]
|
||||
}
|
||||
move_right_p2={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777233,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":1,"button_index":15,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":0,"axis_value":1.0,"script":null)
|
||||
]
|
||||
}
|
||||
shoot_p2={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777350,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777238,"unicode":0,"echo":false,"script":null)
|
||||
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":1,"button_index":2,"pressure":0.0,"pressed":false,"script":null)
|
||||
]
|
||||
}
|
||||
splitscreen={
|
||||
"deadzone": 0.5,
|
||||
"events": [ Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"button_index":10,"pressure":0.0,"pressed":false,"script":null)
|
||||
, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777218,"unicode":0,"echo":false,"script":null)
|
||||
]
|
||||
}
|
||||
|
||||
[layer_names]
|
||||
|
||||
|
||||
@@ -4,6 +4,8 @@ extends Actor
|
||||
|
||||
const FLOOR_DETECT_DISTANCE = 20.0
|
||||
|
||||
export(String) var action_suffix = ""
|
||||
|
||||
onready var platform_detector = $PlatformDetector
|
||||
onready var sprite = $Sprite
|
||||
onready var animation_player = $AnimationPlayer
|
||||
@@ -11,6 +13,17 @@ onready var shoot_timer = $ShootAnimation
|
||||
onready var gun = $Sprite/Gun
|
||||
|
||||
|
||||
func _ready():
|
||||
# Static types are necessary to avoid
|
||||
var camera: Camera2D = $Camera
|
||||
if action_suffix == "_p1":
|
||||
camera.custom_viewport = $"../.."
|
||||
elif action_suffix == "_p2":
|
||||
var viewport: Viewport = $"../../../../ViewportContainer2/Viewport"
|
||||
viewport.world_2d = ($"../.." as Viewport).world_2d
|
||||
camera.custom_viewport = viewport
|
||||
|
||||
|
||||
# Physics process is a built-in loop in Godot.
|
||||
# If you define _physics_process on a node, Godot will call it every frame.
|
||||
|
||||
@@ -32,7 +45,7 @@ onready var gun = $Sprite/Gun
|
||||
func _physics_process(_delta):
|
||||
var direction = get_direction()
|
||||
|
||||
var is_jump_interrupted = Input.is_action_just_released("jump") and _velocity.y < 0.0
|
||||
var is_jump_interrupted = Input.is_action_just_released("jump" + action_suffix) and _velocity.y < 0.0
|
||||
_velocity = calculate_move_velocity(_velocity, direction, speed, is_jump_interrupted)
|
||||
|
||||
var snap_vector = Vector2.DOWN * FLOOR_DETECT_DISTANCE if direction.y == 0.0 else Vector2.ZERO
|
||||
@@ -44,14 +57,14 @@ func _physics_process(_delta):
|
||||
# When the character’s direction changes, we want to to scale the Sprite accordingly to flip it.
|
||||
# This will make Robi face left or right depending on the direction you move.
|
||||
if direction.x != 0:
|
||||
sprite.scale.x = direction.x
|
||||
sprite.scale.x = 1 if direction.x > 0 else -1
|
||||
|
||||
# We use the sprite's scale to store Robi’s look direction which allows us to shoot
|
||||
# bullets forward.
|
||||
# There are many situations like these where you can reuse existing properties instead of
|
||||
# creating new variables.
|
||||
var is_shooting = false
|
||||
if Input.is_action_just_pressed("shoot"):
|
||||
if Input.is_action_just_pressed("shoot" + action_suffix):
|
||||
is_shooting = gun.shoot(sprite.scale.x)
|
||||
|
||||
var animation = get_new_animation(is_shooting)
|
||||
@@ -63,8 +76,8 @@ func _physics_process(_delta):
|
||||
|
||||
func get_direction():
|
||||
return Vector2(
|
||||
Input.get_action_strength("move_right") - Input.get_action_strength("move_left"),
|
||||
-Input.get_action_strength("jump") if is_on_floor() and Input.is_action_just_pressed("jump") else 0.0
|
||||
Input.get_action_strength("move_right" + action_suffix) - Input.get_action_strength("move_left" + action_suffix),
|
||||
-1 if is_on_floor() and Input.is_action_just_pressed("jump" + action_suffix) else 0
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
[gd_scene load_steps=11 format=2]
|
||||
[gd_scene load_steps=12 format=2]
|
||||
|
||||
[ext_resource path="res://assets/art/tileset/tileset.tres" type="TileSet" id=1]
|
||||
[ext_resource path="res://src/Actors/Enemy.tscn" type="PackedScene" id=2]
|
||||
@@ -8,6 +8,7 @@
|
||||
[ext_resource path="res://assets/art/platforms/moving_platform.png" type="Texture" id=6]
|
||||
[ext_resource path="res://src/Level/ParallaxBackground.tscn" type="PackedScene" id=7]
|
||||
[ext_resource path="res://assets/audio/music/music.ogg" type="AudioStream" id=8]
|
||||
[ext_resource path="res://src/Level/Music.gd" type="Script" id=9]
|
||||
|
||||
[sub_resource type="Animation" id=1]
|
||||
resource_name = "move"
|
||||
@@ -263,3 +264,4 @@ position = Vector2( 828.515, 77.262 )
|
||||
[node name="Music" type="AudioStreamPlayer" parent="."]
|
||||
stream = ExtResource( 8 )
|
||||
autoplay = true
|
||||
script = ExtResource( 9 )
|
||||
|
||||
16
2d/platformer/src/Level/Music.gd
Normal file
16
2d/platformer/src/Level/Music.gd
Normal file
@@ -0,0 +1,16 @@
|
||||
extends AudioStreamPlayer
|
||||
|
||||
const DOUBLE_VOLUME_DB = 6 # Do not change. Represents doubling of sound pressure.
|
||||
|
||||
export(int) var base_volume_db = -4
|
||||
|
||||
func _ready():
|
||||
# To avoid AudioStreamPlayer2D sounds playing on top of each other and
|
||||
# being very loud, let's decrease the volume for splitscreen mode, but
|
||||
# increase the music volume to keep the music at the same volume.
|
||||
if get_parent().get_owner().name == "Splitscreen":
|
||||
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), base_volume_db - DOUBLE_VOLUME_DB)
|
||||
volume_db = DOUBLE_VOLUME_DB
|
||||
else:
|
||||
AudioServer.set_bus_volume_db(AudioServer.get_bus_index("Master"), base_volume_db)
|
||||
volume_db = 0
|
||||
@@ -13,6 +13,14 @@ func _init():
|
||||
OS.max_window_size = OS.get_screen_size()
|
||||
|
||||
|
||||
func _notification(what):
|
||||
if what == NOTIFICATION_WM_QUIT_REQUEST:
|
||||
# We need to clean up a little bit first to avoid Viewport errors.
|
||||
if name == "Splitscreen":
|
||||
$Black/SplitContainer/ViewportContainer1.free()
|
||||
$Black.queue_free()
|
||||
|
||||
|
||||
func _input(event):
|
||||
if event.is_action_pressed("toggle_fullscreen"):
|
||||
OS.window_fullscreen = not OS.window_fullscreen
|
||||
@@ -29,3 +37,14 @@ func _input(event):
|
||||
else:
|
||||
_pause_menu.close()
|
||||
get_tree().set_input_as_handled()
|
||||
|
||||
elif event.is_action_pressed("splitscreen"):
|
||||
if name == "Splitscreen":
|
||||
# We need to clean up a little bit first to avoid Viewport errors.
|
||||
$Black/SplitContainer/ViewportContainer1.free()
|
||||
$Black.queue_free()
|
||||
# warning-ignore:return_value_discarded
|
||||
get_tree().change_scene("res://src/Main/Game.tscn")
|
||||
else:
|
||||
# warning-ignore:return_value_discarded
|
||||
get_tree().change_scene("res://src/Main/Splitscreen.tscn")
|
||||
|
||||
80
2d/platformer/src/Main/Splitscreen.tscn
Normal file
80
2d/platformer/src/Main/Splitscreen.tscn
Normal file
@@ -0,0 +1,80 @@
|
||||
[gd_scene load_steps=6 format=2]
|
||||
|
||||
[ext_resource path="res://src/UserInterface/PauseMenu.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://src/Main/Game.gd" type="Script" id=2]
|
||||
[ext_resource path="res://src/Level/Level.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://src/Actors/Player.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://src/Level/ParallaxBackground.tscn" type="PackedScene" id=5]
|
||||
|
||||
[node name="Splitscreen" type="Node"]
|
||||
pause_mode = 2
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="InterfaceLayer" type="CanvasLayer" parent="."]
|
||||
layer = 100
|
||||
|
||||
[node name="PauseMenu" parent="InterfaceLayer" instance=ExtResource( 1 )]
|
||||
|
||||
[node name="Black" type="ColorRect" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_right = 6.10352e-05
|
||||
margin_bottom = 3.05176e-05
|
||||
color = Color( 0, 0, 0, 1 )
|
||||
|
||||
[node name="SplitContainer" type="HSplitContainer" parent="Black"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
dragger_visibility = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ViewportContainer1" type="ViewportContainer" parent="Black/SplitContainer"]
|
||||
margin_right = 394.0
|
||||
margin_bottom = 480.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
stretch = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Viewport" type="Viewport" parent="Black/SplitContainer/ViewportContainer1"]
|
||||
size = Vector2( 394, 480 )
|
||||
size_override_stretch = true
|
||||
handle_input_locally = false
|
||||
usage = 0
|
||||
render_target_update_mode = 3
|
||||
audio_listener_enable_2d = true
|
||||
|
||||
[node name="Level" parent="Black/SplitContainer/ViewportContainer1/Viewport" instance=ExtResource( 3 )]
|
||||
|
||||
[node name="Player1" parent="Black/SplitContainer/ViewportContainer1/Viewport/Level" instance=ExtResource( 4 )]
|
||||
position = Vector2( 90, 546 )
|
||||
action_suffix = "_p1"
|
||||
|
||||
[node name="Player2" parent="Black/SplitContainer/ViewportContainer1/Viewport/Level" instance=ExtResource( 4 )]
|
||||
position = Vector2( 120, 546 )
|
||||
action_suffix = "_p2"
|
||||
|
||||
[node name="ViewportContainer2" type="ViewportContainer" parent="Black/SplitContainer"]
|
||||
margin_left = 406.0
|
||||
margin_right = 800.0
|
||||
margin_bottom = 480.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
stretch = true
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="Viewport" type="Viewport" parent="Black/SplitContainer/ViewportContainer2"]
|
||||
size = Vector2( 394, 480 )
|
||||
size_override_stretch = true
|
||||
handle_input_locally = false
|
||||
usage = 0
|
||||
render_target_update_mode = 3
|
||||
audio_listener_enable_2d = true
|
||||
|
||||
[node name="ParallaxBackground" parent="Black/SplitContainer/ViewportContainer2/Viewport" instance=ExtResource( 5 )]
|
||||
@@ -23,4 +23,7 @@ func _on_ResumeButton_pressed():
|
||||
|
||||
|
||||
func _on_QuitButton_pressed():
|
||||
if get_parent().get_parent().name == "Splitscreen":
|
||||
# We need to clean up a little bit first to avoid Viewport errors.
|
||||
$"../../Black/SplitContainer/ViewportContainer1".free()
|
||||
get_tree().quit()
|
||||
|
||||
Reference in New Issue
Block a user