Basic multiplayer working?

This commit is contained in:
Daniel Flanagan 2021-12-15 16:14:36 -06:00
parent 202c44cabf
commit 384d7bac31
Signed by: lytedev
GPG key ID: 5B2020A0F9921EF4
10 changed files with 166 additions and 64 deletions

View file

@ -24,11 +24,6 @@ flags = 4
atlas = ExtResource( 1 )
region = Rect2( 54, 468, 18, 36 )
[sub_resource type="AtlasTexture" id=9]
flags = 4
atlas = ExtResource( 1 )
region = Rect2( 144, 468, 18, 36 )
[sub_resource type="AtlasTexture" id=5]
flags = 4
atlas = ExtResource( 1 )
@ -49,6 +44,11 @@ flags = 4
atlas = ExtResource( 1 )
region = Rect2( 126, 468, 18, 36 )
[sub_resource type="AtlasTexture" id=9]
flags = 4
atlas = ExtResource( 1 )
region = Rect2( 144, 468, 18, 36 )
[sub_resource type="SpriteFrames" id=10]
animations = [ {
"frames": [ SubResource( 1 ), SubResource( 2 ), SubResource( 3 ), SubResource( 4 ) ],
@ -56,15 +56,15 @@ animations = [ {
"name": "idle",
"speed": 6.0
}, {
"frames": [ SubResource( 9 ) ],
"loop": true,
"name": "hurt",
"speed": 5.0
}, {
"frames": [ SubResource( 5 ), SubResource( 6 ), SubResource( 7 ), SubResource( 8 ) ],
"loop": true,
"name": "run",
"speed": 12.0
}, {
"frames": [ SubResource( 9 ) ],
"loop": true,
"name": "hurt",
"speed": 5.0
} ]
[sub_resource type="ConvexPolygonShape2D" id=11]
@ -81,7 +81,7 @@ modulate = Color( 0.384314, 0.796078, 1, 1 )
position = Vector2( 0, -18 )
frames = SubResource( 10 )
animation = "idle"
frame = 1
frame = 2
playing = true
[node name="collider" type="CollisionShape2D" parent="."]

View file

@ -38,6 +38,40 @@ Global="*res://scripts/global/global.gd"
singletons=[ "res://webrtc/webrtc.tres" ]
[input]
ui_cancel={
"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":16777217,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
, Object(InputEventJoypadButton,"resource_local_to_scene":false,"resource_name":"","device":0,"button_index":1,"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":16777220,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
up={
"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,"physical_scancode":0,"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":16777232,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
down={
"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":83,"physical_scancode":0,"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":16777234,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
left={
"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,"physical_scancode":0,"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":16777231,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
right={
"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,"physical_scancode":0,"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":16777233,"physical_scancode":0,"unicode":0,"echo":false,"script":null)
]
}
[physics]
common/enable_pause_aware_picking=true

View file

@ -1,32 +1,49 @@
[gd_scene load_steps=2 format=2]
[gd_scene load_steps=3 format=2]
[ext_resource path="res://scripts/screens/game.gd" type="Script" id=1]
[ext_resource path="res://assets/theme.tres" type="Theme" id=2]
[node name="game" type="Node2D"]
script = ExtResource( 1 )
[node name="camera" type="Camera2D" parent="."]
offset = Vector2( 100, 0 )
current = true
zoom = Vector2( 0.5, 0.5 )
drag_margin_left = 0.0
drag_margin_top = 0.0
drag_margin_right = 0.0
drag_margin_bottom = 0.0
editor_draw_limits = true
[node name="Label" type="Label" parent="."]
margin_left = 93.0
margin_top = 109.0
margin_right = 253.0
margin_bottom = 123.0
[node name="CanvasLayer" type="CanvasLayer" parent="."]
[node name="ui" type="MarginContainer" parent="CanvasLayer"]
anchor_right = 1.0
anchor_bottom = 1.0
theme = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="v" type="VBoxContainer" parent="CanvasLayer/ui"]
margin_right = 1024.0
margin_bottom = 600.0
[node name="Label" type="Label" parent="CanvasLayer/ui/v"]
margin_right = 1024.0
margin_bottom = 21.0
text = "You are playing the game"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button" type="Button" parent="Label"]
margin_left = 29.0
margin_top = 177.0
margin_right = 120.0
margin_bottom = 197.0
[node name="Button" type="Button" parent="CanvasLayer/ui/v"]
margin_top = 25.0
margin_right = 1024.0
margin_bottom = 52.0
text = "Leave Game"
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="pressed" from="Label/Button" to="." method="_on_Button_pressed"]
[connection signal="pressed" from="CanvasLayer/ui/v/Button" to="." method="_on_Button_pressed"]

View file

@ -1,20 +1,22 @@
[gd_scene load_steps=5 format=2]
[gd_scene load_steps=6 format=2]
[ext_resource path="res://assets/fonts/iosevkalyte/iosevkalyte-regular.ttf" type="DynamicFontData" id=1]
[ext_resource path="res://assets/img/cross.png" type="Texture" id=2]
[ext_resource path="res://scripts/screens/main_menu.gd" type="Script" id=3]
[ext_resource path="res://assets/theme.tres" type="Theme" id=4]
[sub_resource type="DynamicFont" id=1]
size = 70
font_data = ExtResource( 1 )
[node name="Control" type="MarginContainer"]
[node name="main_menu" type="MarginContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 20.0
margin_top = 20.0
margin_right = -20.0
margin_bottom = -20.0
theme = ExtResource( 4 )
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
@ -77,9 +79,9 @@ size_flags_vertical = 3
[node name="v" type="VBoxContainer" parent="v/c"]
margin_left = 124.0
margin_top = 153.0
margin_top = 150.0
margin_right = 859.0
margin_bottom = 352.0
margin_bottom = 356.0
[node name="title" type="Label" parent="v/c/v"]
margin_right = 735.0
@ -93,19 +95,19 @@ valign = 1
[node name="h" type="HBoxContainer" parent="v/c/v"]
margin_top = 185.0
margin_right = 735.0
margin_bottom = 199.0
margin_bottom = 206.0
alignment = 1
[node name="made_by" type="Label" parent="v/c/v/h"]
margin_left = 312.0
margin_right = 371.0
margin_bottom = 14.0
margin_left = 305.0
margin_right = 369.0
margin_bottom = 21.0
text = "made by "
[node name="link" type="LinkButton" parent="v/c/v/h"]
margin_left = 375.0
margin_right = 422.0
margin_bottom = 14.0
margin_left = 373.0
margin_right = 429.0
margin_bottom = 21.0
hint_tooltip = "Open https://lyte.dev"
text = "lytedev"

View file

@ -5,12 +5,14 @@ const SignalledWebRTCMultiplayer = preload("./signalled_webrtc_multiplayer.gd")
onready var client = SignalledWebRTCMultiplayer.new()
onready var onetime_cmd_flags = {
"--singleplayer": false,
"--multiplayer": false,
"--create-lobby": false,
"--join-first-available-lobby": false,
}
func _ready():
get_tree().use_font_oversampling = true
add_child(client)
for flag in onetime_cmd_flags.keys():
if flag in OS.get_cmdline_args():
@ -29,7 +31,7 @@ func main_menu():
goto_scene("main_menu")
func start_singleplayer_game():
client.close()
client.singleplayer()
goto_game()
func goto_game():

View file

@ -78,9 +78,17 @@ func connect_to_signaller(url = signaller_url):
if result != OK:
print("Failed to connect to WebSocket signalling server at %s: %s" % [signaller_url, result])
func singleplayer():
close()
webrtc = WebRTCMultiplayer.new()
webrtc.initialize(1, false)
get_tree().network_peer = webrtc
_create_peer({id = 1})
func close():
if webrtc != null: webrtc.close()
websocket.disconnect_from_host()
get_tree().network_peer = null
func set_display_name(new_display_name: String):
display_name = new_display_name
@ -125,9 +133,11 @@ func send_answer(id, answer) -> int:
return _send_json({"id": id, "answer": answer }, "answer")
func _webrtc_peer_connected(id):
peers[id].connected = true
emit_signal("webrtc_peer_connected", id)
func _webrtc_peer_disconnected(id):
peers[id].connected = false
emit_signal("webrtc_peer_disconnected", id)
func _webrtc_connection_succeeded():
@ -222,8 +232,17 @@ func _create_peer(data):
# this guarantees only one peer sends the offer and that offers are never
# sent to ourselves?
if int(id) > webrtc.get_unique_id(): peer.create_offer()
peers[int(id)] = {
connected = false,
ready = false,
name = "",
}
emit_signal("peer_created", data)
func _delete_peer(id):
if webrtc.has_peer(id): webrtc.remove_peer(id)
if peers.has(id): peers.erase(id)
func _webrtc_offer_created(type, data, id):
print("WebRTC %s created for peer %s" % [type, id])
if not webrtc.has_peer(int(id)): return
@ -237,7 +256,8 @@ func _new_ice_candidate(mid, index, sdp, id):
print("New ICE candidate for peer %s" % id)
send_candidate(id, mid, index, sdp)
func _signaller_peer_left(id): if peers.has(id): peers.delete(id)
func _signaller_peer_left(id):
_delete_peer(id)
func _signaller_peer_data(peers):
for peer in peers:
@ -262,7 +282,7 @@ func _webrtc_answer_received(data):
func _webrtc_candidate_received(data):
if webrtc.has_peer(data.id):
print("Adding ice candidate for peer %s" % data.id)
print("--> Candidate: %s" % JSON.print(data.candidate))
print("--> Candidate: %s" % JSON.print(data))
webrtc.get_peer(data.id).connection.add_ice_candidate(data.mid, data.index, data.sdp)
else:
print("Received candidate for non-existant peer %s" % data.id)

View file

@ -77,18 +77,21 @@ func maybe_hide_health_bar():
func _ready():
# rset_config("acceleration", MultiplayerAPI.RPC_MODE_REMOTESYNC)
# rset_config("velocity", MultiplayerAPI.RPC_MODE_REMOTESYNC)
rset_config("position", MultiplayerAPI.RPC_MODE_SLAVE)
# rset_config("position", MultiplayerAPI.RPC_MODE_SLAVE)
set_display_name(name)
func set_display_name(i_name):
display_name = i_name
if len(get_tree().get_network_connected_peers()) > 1:
name_displayer.text = display_name
else:
name_displayer.text = ""
name_displayer.text = display_name
static func int_input_action(action):
return int(Input.is_action_pressed(action))
static func int_input_action(actions) -> int:
if typeof(actions) == TYPE_ARRAY:
var result = false
for action in actions:
result = result or Input.is_action_pressed(action)
return int(result)
else:
return int(Input.is_action_pressed(actions))
func _physics_process(delta):
self.mana += (10*delta)
@ -101,8 +104,8 @@ func _physics_process(delta):
if collision.collider is RigidBody2D:
collision.collider.apply_central_impulse(-collision.normal * weight)
if is_network_master():
rset_unreliable("position", position)
# if is_network_master():
# rset_unreliable("position", position)
func _process_input():
if is_network_master():
@ -110,8 +113,8 @@ func _process_input():
# probably want to implement a "whichever one was pressed last" so that
# players move as fast as possible without having to worry about switching
# key frame perfectly
iv.x = int_input_action("ui_right") - int_input_action("ui_left")
iv.y = int_input_action("ui_down") - int_input_action("ui_up")
iv.x = int_input_action(["ui_right", "right"]) - int_input_action(["ui_left", "left"])
iv.y = int_input_action(["ui_down", "down"]) - int_input_action(["ui_up", "up"])
rset("acceleration", iv.normalized() * speed)
func _process_animation():

View file

@ -1,26 +1,48 @@
extends Node2D
onready var player = preload("res://objects/player.tscn")
onready var player_obj = preload("res://objects/player.tscn")
onready var camera = $camera
onready var camera_target = null
onready var zoom_levels = [0.25, 0.5, 1, 1.5, 2, 2.5, 3]
onready var current_zoom_level_index = 2
onready var player = null
onready var players = null
func _ready():
# TODO: probably have to wait for all peers to be ready before we add players
rpc("add_player", get_tree().get_network_unique_id())
if Global.client.is_host():
for id in get_tree().get_network_connected_peers():
Global.client.peers[id].ready = false
ready(1)
else:
rpc("ready", get_tree().get_network_unique_id())
func _process(delta):
pass
remotesync func ready(id):
print("Ready %d" % id)
Global.client.peers[id].ready = true
var all_ready = true
for id in Global.client.peers: all_ready = all_ready and Global.client.peers[id].ready
if all_ready: start()
remotesync func add_player(peer_id):
var new_player = player.instance()
new_player.name = Global.negotiator.peer_by_peer_id(peer_id).name
new_player.set_network_master(peer_id)
func start():
print("Starting Game...")
# for each peer
for id in get_tree().get_network_connected_peers():
print("Creating player for peer %d" % id)
rpc("add_player", id)
rpc("add_player", 1)
func _process(_delta):
if player: camera.offset = player.position
remotesync func add_player(id):
var new_player = player_obj.instance()
if id == get_tree().get_network_unique_id(): player = new_player
new_player.name = Global.client.peers[id].name
new_player.set_network_master(id)
add_child(new_player)
new_player.global_position = Vector2(100, 100)
print("Added player: %s for peer %s" % [new_player, peer_id])
new_player.global_position = Vector2(-100 + (id % 200), -100 + (id % 200))
print("Added player: %s for peer %s" % [new_player, id])
func _on_Button_pressed():
Global.main_menu()

View file

@ -6,6 +6,8 @@ func _ready():
$v/h/singleplayer.shortcut = Global.key_shortcut(KEY_S)
if Global.check_onetime_flag("multiplayer"):
_on_multiplayer_pressed()
if Global.check_onetime_flag("singleplayer"):
_on_Singleplayer_pressed()
func _on_Singleplayer_pressed():
Global.start_singleplayer_game()

View file

@ -61,7 +61,7 @@ func _add_peer(id, p):
if p.id == 1: p.ready = true
new_peer.set_with_dict(p)
peers_grid.add_child(new_peer)
peers[id] = new_peer
peers[int(id)] = new_peer
add_chat("> %s joined the lobby" % new_peer.display_name)
func _update_peer(id, peer_data):
@ -123,14 +123,14 @@ func _on_start_pressed():
if is_host: rpc("start_game")
remotesync func start_game():
Global.negotiator.peers = peers
Global.negotiator.peers_id_mappings = peers_id_mappings
# TODO: seal lobby
get_tree().refuse_new_network_connections = true
Global.goto_game()
remotesync func set_ready(ready):
var from = get_tree().get_rpc_sender_id()
print("Set Ready: %s %s" % [from, ready])
Global.client.peers[from].ready = ready
peers[from].ready = ready
if is_host: update_can_start()
func _on_TextEdit_text_entered(_new_text):