Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiplayer #10

Merged
merged 5 commits into from
Nov 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion components/enemy/enemy.gd
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func _on_gravity_changed(new_gravity):


func _on_hitbox_body_entered(body):
if body.name == "Player":
if body.is_in_group("players"):
if squashable and body.velocity.y > 0 and body.position.y < position.y:
body.stomp()
queue_free()
Expand Down
2 changes: 1 addition & 1 deletion components/platform/platform.gd
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func _ready():


func _on_area_2d_body_entered(body):
if not body.name == "Player":
if not body.is_in_group("players"):
return
if fall_time > 0:
fall_timer.start(fall_time)
Expand Down
2 changes: 1 addition & 1 deletion components/player/player.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
radius = 31.0
height = 92.0

[node name="Player" type="CharacterBody2D"]
[node name="Player" type="CharacterBody2D" groups=["players"]]
collision_layer = 3
collision_mask = 5
floor_constant_speed = true
Expand Down
9 changes: 9 additions & 0 deletions doc/MODS.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ on one of these nodes. In the Inspector, you can adjust their behaviour:
These platforms can be made into moving platforms by using Godot's Animation
functionality.

### Multiplayer and player controls

Click on the `Player` node. In the inspector, try changing the Player
dropdown to "Two" or "Both".

Duplicate the `Player` node. Move it next to the existing player. Then
change the Player to "Two" in the duplicated one. Now the game is
multiplayer.

### Player and flag appearance

Click on the `Player` node. In the inspector, observe where it says `Sprite
Expand Down
14 changes: 9 additions & 5 deletions hud.tscn
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,19 @@ anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -194.5
offset_top = -396.0
offset_right = 194.5
offset_bottom = -217.0
offset_left = -367.5
offset_top = -487.0
offset_right = 367.5
offset_bottom = 56.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 4
theme_override_font_sizes/font_size = 64
text = "Press any key
text = "Controls
Player One: Arrow Keys
Player Two: WASD

Press any key
to Start"
horizontal_alignment = 1

Expand Down
63 changes: 63 additions & 0 deletions project.godot
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,69 @@ window/size/window_width_override=960
window/size/window_height_override=540
window/stretch/mode="canvas_items"

[global_group]

players=""

[input]

player_2_up={
"deadzone": 0.5,
"events": [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":87,"physical_keycode":0,"key_label":0,"unicode":119,"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":1,"axis_value":-1.0,"script":null)
]
}
player_2_down={
"deadzone": 0.5,
"events": [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":83,"physical_keycode":0,"key_label":0,"unicode":115,"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":1,"axis_value":1.0,"script":null)
]
}
player_2_left={
"deadzone": 0.5,
"events": [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":65,"physical_keycode":0,"key_label":0,"unicode":97,"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":0,"axis_value":-1.0,"script":null)
]
}
player_2_right={
"deadzone": 0.5,
"events": [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":68,"physical_keycode":0,"key_label":0,"unicode":100,"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)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":1,"axis":2,"axis_value":1.0,"script":null)
]
}
player_1_up={
"deadzone": 0.5,
"events": [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":4194320,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":11,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":-1.0,"script":null)
]
}
player_1_down={
"deadzone": 0.5,
"events": [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":4194322,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":12,"pressure":0.0,"pressed":false,"script":null)
, Object(InputEventJoypadMotion,"resource_local_to_scene":false,"resource_name":"","device":0,"axis":1,"axis_value":1.0,"script":null)
]
}
player_1_left={
"deadzone": 0.5,
"events": [null, Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194319,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":13,"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)
]
}
player_1_right={
"deadzone": 0.5,
"events": [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":4194321,"physical_keycode":0,"key_label":0,"unicode":0,"location":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)
]
}

[layer_names]

2d_physics/layer_1="Player"
Expand Down
1 change: 1 addition & 0 deletions scripts/global.gd
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ signal gravity_changed(gravity: float)
signal timer_added

enum Endings { WIN, LOSE }
enum Player { ONE, TWO, BOTH }

## Timer for finishing the level.
var timer: Timer
Expand Down
61 changes: 58 additions & 3 deletions scripts/player.gd
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@ class_name Player
extends CharacterBody2D
## A player's character, which can walk, jump, and stomp on enemies.

const _PLAYER_ACTIONS = {
Global.Player.ONE:
{
"jump": "player_1_up",
"left": "player_1_left",
"right": "player_1_right",
},
Global.Player.TWO:
{
"jump": "player_2_up",
"left": "player_2_left",
"right": "player_2_right",
},
}

## Which player controls this character?
@export var player: Global.Player = Global.Player.ONE

## Use this to change the sprite frames of your character.
@export var sprite_frames: SpriteFrames = _initial_sprite_frames:
set = _set_sprite_frames
Expand Down Expand Up @@ -104,6 +122,43 @@ func stomp():
_jump()


func _player_just_pressed(action):
if player == Global.Player.BOTH:
return (
Input.is_action_just_pressed(_PLAYER_ACTIONS[Global.Player.ONE][action])
or Input.is_action_just_pressed(_PLAYER_ACTIONS[Global.Player.TWO][action])
)
return Input.is_action_just_pressed(_PLAYER_ACTIONS[player][action])


func _player_just_released(action):
if player == Global.Player.BOTH:
return (
Input.is_action_just_released(_PLAYER_ACTIONS[Global.Player.ONE][action])
or Input.is_action_just_released(_PLAYER_ACTIONS[Global.Player.TWO][action])
)
return Input.is_action_just_released(_PLAYER_ACTIONS[player][action])


func _get_player_axis(action_a, action_b):
if player == Global.Player.BOTH:
return clamp(
(
Input.get_axis(
_PLAYER_ACTIONS[Global.Player.ONE][action_a],
_PLAYER_ACTIONS[Global.Player.ONE][action_b]
)
+ Input.get_axis(
_PLAYER_ACTIONS[Global.Player.TWO][action_a],
_PLAYER_ACTIONS[Global.Player.TWO][action_b]
)
),
-1,
1
)
return Input.get_axis(_PLAYER_ACTIONS[player][action_a], _PLAYER_ACTIONS[player][action_b])


func _physics_process(delta):
# Don't move if there are no lives left.
if Global.lives <= 0:
Expand All @@ -114,15 +169,15 @@ func _physics_process(delta):
coyote_timer = (coyote_time + delta)
double_jump_armed = false

if Input.is_action_just_pressed("ui_accept"):
if _player_just_pressed("jump"):
jump_buffer_timer = (jump_buffer + delta)

if jump_buffer_timer > 0 and (double_jump_armed or coyote_timer > 0):
_jump()

# Reduce velocity if the player lets go of the jump key before the apex.
# This allows controlling the height of the jump.
if Input.is_action_just_released("ui_accept") and velocity.y < 0:
if _player_just_released("jump") and velocity.y < 0:
velocity.y *= (1 - (jump_cut_factor / 100.00))

# Add the gravity.
Expand All @@ -131,7 +186,7 @@ func _physics_process(delta):

# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var direction = Input.get_axis("ui_left", "ui_right")
var direction = _get_player_axis("left", "right")
if direction:
velocity.x = move_toward(
velocity.x,
Expand Down