[2D Platformer] Add a splitscreen mode

This commit is contained in:
Aaron Franke
2020-03-06 01:27:29 -05:00
parent f5f72e6d3e
commit ebc435074b
7 changed files with 199 additions and 6 deletions

View File

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

View File

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

View File

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

View 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

View File

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

View 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 )]

View File

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