simple multiplayer: Code style enhancements

This commit is contained in:
Rémi Verschelde
2016-09-02 16:07:12 +02:00
parent e435b79e2a
commit c0e3b4161f
7 changed files with 208 additions and 266 deletions

View File

@@ -1,34 +1,23 @@
extends Area2D
# member variables here, example:
# var a=2
# var b="textvar"
var in_area = []
var owner
#called from the animation
# Called from the animation
func explode():
if (not is_network_master()):
#but will call explosion only on master
# But will call explosion only on master
return
for p in in_area:
if (p.has_method("exploded")):
p.rpc("exploded",owner) #exploded has a master keyword, so it will only be received by the master
p.rpc("exploded", owner) # Exploded has a master keyword, so it will only be received by the master
func done():
queue_free()
func _ready():
# Called every time the node is added to the scene.
# Initialization here
pass
func _on_bomb_body_enter( body ):
func _on_bomb_body_enter(body):
if (not body in in_area):
in_area.append(body)
func _on_bomb_body_exit( body ):
func _on_bomb_body_exit(body):
in_area.erase(body)

View File

@@ -1,70 +1,67 @@
extends Node
#default game port
# Default game port
const DEFAULT_PORT = 10567
#name for my player
# Name for my player
var player_name = "The Warrior"
#names for remote players in id:name format
# Names for remote players in id:name format
var players = {}
#signals to let lobby GUI know what's going on
# Signals to let lobby GUI know what's going on
signal player_list_changed()
signal connection_failed()
signal connection_succeeded()
signal game_ended()
signal game_error(what)
# callback from SceneTree
# Callback from SceneTree
func _player_connected(id):
#this is not used, because _connected_ok is called for clients on success and will do the job.
pass
# callback from SceneTree
func _player_disconnected(id):
# This is not used in this demo, because _connected_ok is called for clients
# on success and will do the job.
pass
# Callback from SceneTree
func _player_disconnected(id):
if (get_tree().is_network_server()):
if (has_node("/root/world")): # game is in progress
emit_signal("game_error","Player "+players[id]+" disconnected")
if (has_node("/root/world")): # Game is in progress
emit_signal("game_error", "Player " + players[id] + " disconnected")
end_game()
else: #game is not in progress
#if we are the server, send to the new dude all the already registered playes
else: # Game is not in progress
# If we are the server, send to the new dude all the already registered players
unregister_player(id)
for p_id in players:
#erase in the server
rpc_id( p_id, "unregister_player", id)
# callback from SceneTree, only for clients (not server)
# Erase in the server
rpc_id(p_id, "unregister_player", id)
# Callback from SceneTree, only for clients (not server)
func _connected_ok():
#Registration of a client beings here, Tell everyone that we are here
rpc( "register_player", get_tree().get_network_unique_id(), player_name )
# Registration of a client beings here, tell everyone that we are here
rpc("register_player", get_tree().get_network_unique_id(), player_name)
emit_signal("connection_succeeded")
# callback from SceneTree, only for clients (not server)
# Callback from SceneTree, only for clients (not server)
func _server_disconnected():
emit_signal("game_error","Server disconnected")
emit_signal("game_error", "Server disconnected")
end_game()
# callback from SceneTree, only for clients (not server)
# Callback from SceneTree, only for clients (not server)
func _connected_fail():
get_tree().set_network_peer(null) #remove peer
emit_signal("connection_failed")
get_tree().set_network_peer(null) # Remove peer
emit_signal("connection_failed")
# Lobby management functions
# lobby management functions
remote func register_player(id, name):
if (get_tree().is_network_server()):
#if we are the server, let everyone know about the new players
rpc_id( id, "register_player", 1, player_name ) # send myself to new dude
for p_id in players: #then, for each remoe player
rpc_id( id, "register_player", p_id, players[p_id] ) # send player to new dude
rpc_id( p_id, "register_player", id, name ) # send new dude to player
players[id]=name
# If we are the server, let everyone know about the new players
rpc_id(id, "register_player", 1, player_name) # Send myself to new dude
for p_id in players: # Then, for each remote player
rpc_id(id, "register_player", p_id, players[p_id]) # Send player to new dude
rpc_id(p_id, "register_player", id, name) # Send new dude to player
players[id] = name
emit_signal("player_list_changed")
remote func unregister_player(id):
@@ -72,74 +69,69 @@ remote func unregister_player(id):
emit_signal("player_list_changed")
remote func pre_start_game(spawn_points):
#change scene
# Change scene
var world = load("res://world.tscn").instance()
get_tree().get_root().add_child(world)
get_tree().get_root().get_node("lobby").hide()
var player_scene = load("res://player.tscn")
for p in spawn_points:
var spawn_pos = world.get_node("spawn_points/"+str(spawn_points[p])).get_pos()
for p in spawn_points:
var spawn_pos = world.get_node("spawn_points/" + str(spawn_points[p])).get_pos()
var player = player_scene.instance()
player.set_name( str(p) ) #use unique ID as node name
player.set_name(str(p)) # Use unique ID as node name
player.set_pos(spawn_pos)
if (p == get_tree().get_network_unique_id() ):
# if node for this peer id, set master
player.set_network_mode( NETWORK_MODE_MASTER )
player.set_player_name( player_name )
if (p == get_tree().get_network_unique_id()):
# If node for this peer id, set master
player.set_network_mode(NETWORK_MODE_MASTER)
player.set_player_name(player_name)
else:
# otherwise set slave
player.set_network_mode( NETWORK_MODE_SLAVE )
player.set_player_name( players[p] )
# Otherwise set slave
player.set_network_mode(NETWORK_MODE_SLAVE)
player.set_player_name(players[p])
world.get_node("players").add_child(player)
#set up score
world.get_node("score").add_player(get_tree().get_network_unique_id(),player_name)
for pn in players:
world.get_node("score").add_player(pn,players[pn])
if (not get_tree().is_network_server()):
#tell server we are ready to start
rpc_id(1,"ready_to_start", get_tree().get_network_unique_id() )
elif players.size()==0:
# Set up score
world.get_node("score").add_player(get_tree().get_network_unique_id(), player_name)
for pn in players:
world.get_node("score").add_player(pn, players[pn])
if (not get_tree().is_network_server()):
# Tell server we are ready to start
rpc_id(1, "ready_to_start", get_tree().get_network_unique_id())
elif players.size() == 0:
post_start_game()
remote func post_start_game():
get_tree().set_pause(false) #unpause and unleash the game!
get_tree().set_pause(false) # Unpause and unleash the game!
var players_ready = []
remote func ready_to_start(id):
assert( get_tree().is_network_server() )
assert(get_tree().is_network_server())
if (not id in players_ready):
players_ready.append(id)
if (players_ready.size() == players.size()):
for p in players:
rpc_id(p, "post_start_game" )
rpc_id(p, "post_start_game")
post_start_game()
func host_game( name ):
player_name=name
func host_game(name):
player_name = name
var host = NetworkedMultiplayerENet.new()
host.create_server(DEFAULT_PORT,4)
host.create_server(DEFAULT_PORT, 4)
get_tree().set_network_peer(host)
func join_game(ip, name):
player_name=name
player_name = name
var host = NetworkedMultiplayerENet.new()
host.create_client(ip,DEFAULT_PORT)
host.create_client(ip, DEFAULT_PORT)
get_tree().set_network_peer(host)
func get_player_list():
@@ -149,36 +141,33 @@ func get_player_name():
return player_name
func begin_game():
assert ( get_tree().is_network_server() )
#create a dictionary with peer id and respective spawn points, could be improved by randomizing
var spawn_points={}
spawn_points[1]=0 #server in spawn point 0
assert(get_tree().is_network_server())
# Create a dictionary with peer id and respective spawn points, could be improved by randomizing
var spawn_points = {}
spawn_points[1] = 0 # Server in spawn point 0
var spawn_point_idx = 1
for p in players:
spawn_points[p]=spawn_point_idx
spawn_point_idx+=1
#call to pre-start game with the spawn points
spawn_points[p] = spawn_point_idx
spawn_point_idx += 1
# Call to pre-start game with the spawn points
for p in players:
rpc_id(p, "pre_start_game", spawn_points )
pre_start_game( spawn_points )
rpc_id(p, "pre_start_game", spawn_points)
pre_start_game(spawn_points)
func end_game():
if (has_node("/root/world")): # game is in progress
#end it
if (has_node("/root/world")): # Game is in progress
# End it
get_node("/root/world").queue_free()
emit_signal("game_ended")
players.clear()
get_tree().set_network_peer( null ) #end networking
get_tree().set_network_peer(null) # End networking
func _ready():
get_tree().connect("network_peer_connected",self,"_player_connected")
get_tree().connect("network_peer_disconnected",self,"_player_disconnected")
get_tree().connect("connected_to_server",self,"_connected_ok")
get_tree().connect("connection_failed",self,"_connected_fail")
get_tree().connect("server_disconnected",self,"_server_disconnected")
get_tree().connect("network_peer_connected", self, "_player_connected")
get_tree().connect("network_peer_disconnected", self,"_player_disconnected")
get_tree().connect("connected_to_server", self, "_connected_ok")
get_tree().connect("connection_failed", self, "_connected_fail")
get_tree().connect("server_disconnected", self, "_server_disconnected")

View File

@@ -1,72 +1,61 @@
extends Control
const DEFAULT_PORT = 10567
func _ready():
# Called every time the node is added to the scene.
# Initialization here
gamestate.connect("connection_failed",self,"_on_connection_failed")
gamestate.connect("connection_succeeded",self,"_on_connection_success")
gamestate.connect("player_list_changed",self,"refresh_lobby")
gamestate.connect("game_ended",self,"_on_game_ended")
gamestate.connect("game_error",self,"_on_game_error")
pass
gamestate.connect("connection_failed", self, "_on_connection_failed")
gamestate.connect("connection_succeeded", self, "_on_connection_success")
gamestate.connect("player_list_changed", self, "refresh_lobby")
gamestate.connect("game_ended", self, "_on_game_ended")
gamestate.connect("game_error", self, "_on_game_error")
func _on_host_pressed():
if (get_node("connect/name").get_text()==""):
if (get_node("connect/name").get_text() == ""):
get_node("connect/error_label").set_text("Invalid name!")
return
get_node("connect").hide()
get_node("connect").hide()
get_node("players").show()
get_node("connect/error_label").set_text("")
var name = get_node("connect/name").get_text()
gamestate.host_game( name )
gamestate.host_game(name)
refresh_lobby()
func _on_join_pressed():
if (get_node("connect/name").get_text()==""):
if (get_node("connect/name").get_text() == ""):
get_node("connect/error_label").set_text("Invalid name!")
return
var ip = get_node("connect/ip").get_text()
if (not ip.is_valid_ip_address()):
get_node("connect/error_label").set_text("Invalid IPv4 Address!")
get_node("connect/error_label").set_text("Invalid IPv4 address!")
return
get_node("connect/error_label").set_text("")
get_node("connect/host").set_disabled(true)
get_node("connect/join").set_disabled(true)
get_node("players/start").set_disabled(true)
var name = get_node("connect/name").get_text()
gamestate.join_game(ip,name)
gamestate.join_game(ip, name)
refresh_lobby()
func _on_connection_success():
get_node("connect").hide()
get_node("connect").hide()
get_node("players").show()
func _on_connection_failed():
get_node("connect/host").set_disabled(false)
get_node("connect/join").set_disabled(false)
get_node("connect/error_label").set_text("Connection Failed")
get_node("connect/error_label").set_text("Connection failed.")
func _on_game_ended():
show()
get_node("connect").show()
get_node("connect").show()
get_node("players").hide()
get_node("connect/host").set_disabled(false)
get_node("connect/join").set_disabled(false)
func _on_game_error(errtxt):
get_node("error").set_text(errtxt)
get_node("error").popup_centered_minsize()
@@ -75,11 +64,11 @@ func refresh_lobby():
var players = gamestate.get_player_list()
players.sort()
get_node("players/list").clear()
get_node("players/list").add_item(gamestate.get_player_name()+" (You)")
get_node("players/list").add_item(gamestate.get_player_name() + " (You)")
for p in players:
get_node("players/list").add_item(p)
get_node("players/start").set_disabled( not get_tree().is_network_server() )
get_node("players/start").set_disabled(not get_tree().is_network_server())
func _on_start_pressed():
gamestate.begin_game()

View File

@@ -1,4 +1,3 @@
extends KinematicBody2D
const MOTION_SPEED = 90.0
@@ -6,100 +5,94 @@ const MOTION_SPEED = 90.0
slave var slave_pos = Vector2()
slave var slave_motion = Vector2()
export var stunned=false
export var stunned = false
#use sync because it will be called everywhere
sync func setup_bomb(name,pos,by_who):
# Use sync because it will be called everywhere
sync func setup_bomb(name, pos, by_who):
var bomb = preload("res://bomb.tscn").instance()
bomb.set_name( name ) #ensure unique name for the bomb
bomb.set_pos( pos )
bomb.owner=by_who
#no need to set network mode to bomb, will be owned by master by
#default
bomb.set_name(name) # Ensure unique name for the bomb
bomb.set_pos(pos)
bomb.owner = by_who
# No need to set network mode to bomb, will be owned by master by default
get_node("../..").add_child(bomb)
var current_anim=""
var prev_bombing=false
var bomb_index=0
var current_anim = ""
var prev_bombing = false
var bomb_index = 0
func _fixed_process(delta):
var motion = Vector2()
if ( is_network_master() ):
if (is_network_master()):
if (Input.is_action_pressed("move_left")):
motion+=Vector2(-1, 0)
motion += Vector2(-1, 0)
if (Input.is_action_pressed("move_right")):
motion+=Vector2( 1, 0)
motion += Vector2(1, 0)
if (Input.is_action_pressed("move_up")):
motion+=Vector2( 0,-1)
motion += Vector2(0, -1)
if (Input.is_action_pressed("move_down")):
motion+=Vector2( 0, 1)
motion += Vector2(0, 1)
var bombing = Input.is_action_pressed("set_bomb")
if (stunned):
bombing=false
motion=Vector2()
bombing = false
motion = Vector2()
if (bombing and not prev_bombing):
var bomb_name = get_name() + str(bomb_index)
var bomb_pos = get_pos()
rpc("setup_bomb",bomb_name, bomb_pos, get_tree().get_network_unique_id() )
prev_bombing=bombing
motion*=delta
rset("slave_motion",motion)
rset("slave_pos",get_pos())
rpc("setup_bomb", bomb_name, bomb_pos, get_tree().get_network_unique_id())
prev_bombing = bombing
motion *= delta
rset("slave_motion", motion)
rset("slave_pos", get_pos())
else:
set_pos(slave_pos)
motion = slave_motion
var new_anim="standing"
if (motion.y<0):
new_anim="walk_up"
elif (motion.y>0):
new_anim="walk_down"
elif (motion.x<0):
new_anim="walk_left"
elif (motion.x>0):
new_anim="walk_right"
var new_anim = "standing"
if (motion.y < 0):
new_anim = "walk_up"
elif (motion.y > 0):
new_anim = "walk_down"
elif (motion.x < 0):
new_anim = "walk_left"
elif (motion.x > 0):
new_anim = "walk_right"
if (stunned):
new_anim="stunned"
if (new_anim!=current_anim):
current_anim=new_anim
new_anim = "stunned"
if (new_anim != current_anim):
current_anim = new_anim
get_node("anim").play(current_anim)
var remainder = move( motion * MOTION_SPEED )
# FIXME: Use move_and_slide
var remainder = move(motion*MOTION_SPEED)
if (is_colliding()):
#slide through walls
move( get_collision_normal().slide( remainder ) )
if ( not is_network_master() ):
slave_pos = get_pos() # to avoid jitter
# Slide through walls
move(get_collision_normal().slide(remainder))
if (not is_network_master()):
slave_pos = get_pos() # To avoid jitter
slave func stun():
stunned=true
stunned = true
master func exploded(by_who):
if (stunned):
return
stun()
rpc("stun")
rpc("stun") # Stun slaves
stun() # Stun master - could use sync to do both at once
func set_player_name(name):
get_node("Label").set_text(name)
get_node("label").set_text(name)
func _ready():
stunned=false
slave_pos=get_pos()
stunned = false
slave_pos = get_pos()
set_fixed_process(true)
pass

View File

@@ -16,7 +16,7 @@ length = 0.8
loop = true
step = 0.1
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 0, 4, 8, 12 ] }
@@ -28,12 +28,12 @@ length = 1.2
loop = false
step = 0.1
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0 ), "transitions":FloatArray( 1 ), "update":1, "values":[ 0 ] }
tracks/1/type = "value"
tracks/1/path = NodePath("Sprite:transform/rot")
tracks/1/path = NodePath("sprite:transform/rot")
tracks/1/interp = 1
tracks/1/imported = false
tracks/1/keys = { "times":FloatArray( 0, 1, 1.1 ), "transitions":FloatArray( 1, 0, 1 ), "update":0, "values":[ 0.0, 720.0, 0.0 ] }
@@ -49,7 +49,7 @@ length = 0.8
loop = true
step = 0.1
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 0, 4, 8, 12 ] }
@@ -60,7 +60,7 @@ length = 0.8
loop = true
step = 0.2
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 1, 5, 9, 13 ] }
@@ -71,7 +71,7 @@ length = 0.8
loop = true
step = 0.2
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 3, 7, 11, 15 ] }
@@ -82,7 +82,7 @@ length = 0.8
loop = true
step = 0.2
tracks/0/type = "value"
tracks/0/path = NodePath("Sprite:frame")
tracks/0/path = NodePath("sprite:frame")
tracks/0/interp = 1
tracks/0/imported = false
tracks/0/keys = { "times":FloatArray( 0, 0.2, 0.4, 0.6 ), "transitions":FloatArray( 1, 1, 1, 1 ), "update":1, "values":[ 2, 6, 10, 14 ] }
@@ -106,7 +106,7 @@ collision/margin = 0.08
script/script = ExtResource( 1 )
stunned = false
[node name="Sprite" type="Sprite" parent="."]
[node name="sprite" type="Sprite" parent="."]
transform/pos = Vector2( 0.0750351, 6.23615 )
texture = ExtResource( 2 )
@@ -131,13 +131,12 @@ anims/walk_down = SubResource( 4 )
anims/walk_left = SubResource( 5 )
anims/walk_right = SubResource( 6 )
anims/walk_up = SubResource( 7 )
next/walk_down = ""
playback/active = true
playback/speed = 1.0
blend_times = [ ]
autoplay = ""
[node name="Label" type="Label" parent="."]
[node name="label" type="Label" parent="."]
visibility/opacity = 0.7
focus/ignore_mouse = true

View File

@@ -1,14 +1,11 @@
extends KinematicBody2D
#sent to everyone else
# Sent to everyone else
slave func do_explosion():
get_node("anim").play("explode")
#received by owner of the rock
# Received by owner of the rock
master func exploded(by_who):
rpc("do_explosion") #re-sent to slave rocks
get_node("../../score").rpc("increase_score",by_who)
rpc("do_explosion") # Re-sent to slave rocks
get_node("../../score").rpc("increase_score", by_who)
do_explosion()

View File

@@ -1,56 +1,42 @@
extends HBoxContainer
# member variables here, example:
# var a=2
# var b="textvar"
var player_labels={}
var player_labels = {}
func _process(delta):
var rocks_left = get_node("../rocks").get_child_count()
if (rocks_left==0):
if (rocks_left == 0):
var winner_name = ""
var winner_score = 0
for p in player_labels:
if (player_labels[p].score > winner_score):
winner_score=player_labels[p].score
winner_name=player_labels[p].name
get_node("../winner").set_text("THE WINNER IS:\n"+winner_name)
get_node("../winner").show()
winner_score = player_labels[p].score
winner_name = player_labels[p].name
get_node("../winner").set_text("THE WINNER IS:\n" + winner_name)
get_node("../winner").show()
sync func increase_score(for_who):
assert( for_who in player_labels )
assert(for_who in player_labels)
var pl = player_labels[for_who]
pl.score+=1
pl.label.set_text( pl.name+"\n"+str(pl.score) )
pl.score += 1
pl.label.set_text(pl.name + "\n" + str(pl.score))
func add_player(id,name):
func add_player(id, name):
var l = Label.new()
l.set_align(Label.ALIGN_CENTER)
l.set_text(name+"\n"+"0")
l.set_text(name + "\n" + "0")
l.set_h_size_flags(SIZE_EXPAND_FILL)
var font = DynamicFont.new()
font.set_size(18)
font.set_font_data( preload("res://montserrat.otf" ) )
l.add_font_override("font",font)
font.set_font_data(preload("res://montserrat.otf"))
l.add_font_override("font", font)
add_child(l)
player_labels[id]={ name=name, label=l, score=0 }
player_labels[id] = { name = name, label = l, score = 0 }
func _ready():
get_node("../winner").hide()
set_process(true)
func _on_exit_game_pressed():
gamestate.end_game()