Skip to content

Commit

Permalink
Merge pull request #10 from endlessm/multiplayer
Browse files Browse the repository at this point in the history
Multiplayer
  • Loading branch information
starnight authored Nov 12, 2024
2 parents f797399 + 093f8bf commit 5adf7a4
Show file tree
Hide file tree
Showing 8 changed files with 143 additions and 11 deletions.
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

0 comments on commit 5adf7a4

Please sign in to comment.