diff --git a/godot_ship/scenes/Game/Board.tscn b/godot_ship/scenes/Game/Board.tscn index 3410f58..75ca79a 100644 --- a/godot_ship/scenes/Game/Board.tscn +++ b/godot_ship/scenes/Game/Board.tscn @@ -1,7 +1,7 @@ [gd_scene load_steps=3 format=2] [ext_resource path="res://script/game/Gameplay/Board.gd" type="Script" id=1] -[ext_resource path="res://assets/game/board_dark.png" type="Texture" id=2] +[ext_resource path="res://assets/game/board_blue.png" type="Texture" id=2] [node name="Board" type="Node2D"] position = Vector2( 36, 36 ) diff --git a/godot_ship/scenes/Game/Game.tscn b/godot_ship/scenes/Game/Game.tscn index 5d8d8d9..e585187 100644 --- a/godot_ship/scenes/Game/Game.tscn +++ b/godot_ship/scenes/Game/Game.tscn @@ -29,7 +29,7 @@ margin_right = 88.0 margin_bottom = 20.0 text = "Forfeit" -[node name="ConfirmationDialog" type="ConfirmationDialog" parent="."] +[node name="Forfeit Confirmation" type="ConfirmationDialog" parent="."] anchor_left = 0.5 anchor_top = 0.5 anchor_right = 0.5 @@ -54,6 +54,13 @@ margin_right = 43.4668 margin_bottom = 26.1478 text = "Win" +[node name="Connection Error" type="AcceptDialog" parent="."] +margin_right = 230.0 +margin_bottom = 58.0 +window_title = "Connection Error" +dialog_text = "Host disconnected unexpectedly." + [connection signal="pressed" from="Buttons/Forfeit" to="." method="_on_Forfeit_pressed"] -[connection signal="confirmed" from="ConfirmationDialog" to="." method="_on_ConfirmationDialog_confirmed"] +[connection signal="confirmed" from="Forfeit Confirmation" to="." method="_on_Forfeit_Confirmation_confirmed"] [connection signal="button_down" from="Button" to="." method="_on_Button_button_down"] +[connection signal="confirmed" from="Connection Error" to="." method="_on_Connection_Error_confirmed"] diff --git a/godot_ship/scenes/Game/Victory.tscn b/godot_ship/scenes/Game/Victory.tscn index 4397295..c6052df 100644 --- a/godot_ship/scenes/Game/Victory.tscn +++ b/godot_ship/scenes/Game/Victory.tscn @@ -10,25 +10,12 @@ font_data = ExtResource( 2 ) [node name="Victory" type="Control"] anchor_right = 1.0 anchor_bottom = 1.0 +mouse_filter = 2 script = ExtResource( 1 ) __meta__ = { "_edit_use_anchors_": false } -[node name="Label" type="Label" parent="."] -margin_left = 118.32 -margin_top = 44.5109 -margin_right = 260.32 -margin_bottom = 84.5109 -size_flags_vertical = 0 -custom_fonts/font = SubResource( 1 ) -text = "Victory" -align = 1 -valign = 1 -__meta__ = { -"_edit_use_anchors_": false -} - [node name="exit_to_main" type="Button" parent="."] margin_left = 541.0 margin_top = 327.85 @@ -47,6 +34,20 @@ margin_right = 63.2202 margin_bottom = 357.41 text = "Restart" +[node name="Victory" type="Label" parent="."] +margin_left = 380.0 +margin_top = 44.5109 +margin_right = 260.32 +margin_bottom = 84.5109 +size_flags_vertical = 0 +custom_fonts/font = SubResource( 1 ) +text = "Victory" +align = 1 +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} + [connection signal="button_down" from="exit_to_main" to="." method="_on_exit_to_main_button_down"] [connection signal="pressed" from="exit_to_main" to="." method="_on_Button_pressed"] [connection signal="button_down" from="Button2" to="." method="_on_restart_button_down"] diff --git a/godot_ship/scenes/Lobby.tscn b/godot_ship/scenes/Lobby.tscn index 59f98d2..e8ab806 100644 --- a/godot_ship/scenes/Lobby.tscn +++ b/godot_ship/scenes/Lobby.tscn @@ -93,9 +93,19 @@ text = "Connect to Game" [node name="Connected Options" type="VBoxContainer" parent="Lobby Options"] visible = false -margin_top = 84.0 +margin_top = 36.0 margin_right = 123.0 -margin_bottom = 104.0 +margin_bottom = 56.0 + +[node name="Host Options" type="VBoxContainer" parent="Lobby Options/Connected Options"] +visible = false +margin_right = 123.0 +margin_bottom = 20.0 + +[node name="Start Game" type="Button" parent="Lobby Options/Connected Options/Host Options"] +margin_right = 123.0 +margin_bottom = 20.0 +text = "Start Game" [node name="Disconnect Button" type="Button" parent="Lobby Options/Connected Options"] margin_right = 123.0 @@ -162,6 +172,7 @@ text = "127.0.0.1" [connection signal="pressed" from="Lobby Options/Host or Connect/Host Button" to="." method="_on_Host_Button_pressed"] [connection signal="pressed" from="Lobby Options/Host or Connect/Connect Button" to="." method="_on_Connect_Button_pressed"] +[connection signal="pressed" from="Lobby Options/Connected Options/Host Options/Start Game" to="." method="_on_Start_Game_pressed"] [connection signal="pressed" from="Lobby Options/Connected Options/Disconnect Button" to="." method="_on_Disconnect_Button_pressed"] [connection signal="pressed" from="Lobby Options/Change Name Button" to="." method="_on_Change_Name_Button_pressed"] [connection signal="pressed" from="Lobby Options/Exit Lobby Button" to="." method="_on_Exit_Lobby_pressed"] diff --git a/godot_ship/script/Main.gd b/godot_ship/script/Main.gd index 34f2dd8..c7caaf9 100644 --- a/godot_ship/script/Main.gd +++ b/godot_ship/script/Main.gd @@ -60,7 +60,7 @@ func _on_scene_start(scene): var instance #print ("_on_scene_start(",scene,")") match scene: - "Singleplayer": + "Gameplay": instance = Game.instance() add_child (instance) return true diff --git a/godot_ship/script/game/Gameplay/Board.gd b/godot_ship/script/game/Gameplay/Board.gd index fd72f58..e482ec8 100644 --- a/godot_ship/script/game/Gameplay/Board.gd +++ b/godot_ship/script/game/Gameplay/Board.gd @@ -10,6 +10,7 @@ enum {MISS = -1, READY = 0, HIT = 1, SUNK = 2, LOST = 3} var bottom_board:Array # Player board var top_board:Array # Opponent board var ships = [] # list of Ships +var ship_data = [] # Data used to generate ships var ship_count = 0 # number of 'active' (un-sunk) ships # a board is square. This is its side length @@ -33,50 +34,55 @@ func hit(pos): var res = MISS # Get the ship-metadata for that location var ship = bottom_board[pos.x][pos.y] - # If there's a ship there, which exists, and hasn't been hit, - if ship and ship[0] > NO_SHIP and ship[1] == READY: - # Hit the ship, and store whether HIT or SUNK + # If the ship's already been hit here, don't bother beating it again + if ship[1] != READY: + return ship[1] + if ship[0] > NO_SHIP: + # Decide whether HIT or SUNK res = ships[ship[0]].hit(pos) - # TODO: display KABOOM - # Update the ship - ships[ship[0]].update() - # Mark the ship as hit - ship[1] = HIT - else: - # Mark that position as a miss, with no ship - bottom_board[pos.x][pos.y] = [NO_SHIP, MISS] # If ship sunk, if res == SUNK: # remove it from the count ship_count -= 1 - # If no ships left, + # If we have no more ships left, we LOST if ship_count == 0: - # Game has been lost - res = LOST; + res = LOST + # Record the result on the board, and return it + ship[1] = res return res # fire: Store the results of firing on an opponent # pos: board position fired on # res: result of firing on the opponent func fire(pos, res): - if top_board[pos.x][pos.y] == null: + if top_board[pos.x][pos.y] == READY: top_board[pos.x][pos.y] = res - return true - return false + return res + else: + return top_board[pos.x][pos.y] # Place a ship on the board at board-space coordinates func place_ship(in_position, in_size, in_orientation, in_variant = 0): + # Save the ship data + ship_data.append([in_position, in_size, in_orientation]) + # Create a new Ship, and give it some data var ship = Ship.instance() ship._init(in_position, in_size, in_orientation, in_variant) + # Mark the ship on the board for pos in ship.get_extent(): bottom_board[pos.x][pos.y] = [ships.size(), READY] + # Add the ship to the ships array, and keep count ships.append(ship) ship_count += 1 + # Add the ship to the scene tree add_child(ship) -# Not sure why this is necessary yet -func get_bottom_board(): - return bottom_board + +func query_bottom(pos): + return bottom_board[pos.x][pos.y] + +func query_top(pos): + return top_board[pos.x][pos.y] # Get the number of live ships func get_ship_count(): @@ -84,16 +90,16 @@ func get_ship_count(): # _init: Constructor func _init(): - # Initialize the bottom_board to a 10x10 array - for _row in range(board_len): + # Initialize the bottom_board to a len*len array + for x in board_len: bottom_board.append([]) - for column in bottom_board: - column.resize(10) - # Initialize the top_board to a 10x10 array - for _row in range(board_len): + for y in board_len: + bottom_board[x].append([NO_SHIP, READY]) + # Initialize the top_board to a len*len array + for x in board_len: top_board.append([]) - for column in top_board: - column.resize(board_len) + for y in board_len: + top_board[x].append(READY) # worldspace_to_boardspace: convert a Vector2 in world-space to board-space func worldspace_to_boardspace(coordinate:Vector2): diff --git a/godot_ship/script/game/Gameplay/Fire.gd b/godot_ship/script/game/Gameplay/Fire.gd index a172f14..3e1eccc 100644 --- a/godot_ship/script/game/Gameplay/Fire.gd +++ b/godot_ship/script/game/Gameplay/Fire.gd @@ -1,19 +1,20 @@ extends Control +# Signal to pass the fire location back to parent +signal fire_at + var atlas = preload("res://assets/game/HitMissAtlas.png") var sprites = [] -var hits = [] +var hits # Called when the node enters the scene tree for the first time. func _ready(): + print("Fire: _ready()") + for x in 10: + for y in 10: + texture(Vector2(x,y)) pass # Replace with function body. -# Signal to pass the fire location back to yet-unknown nodes -signal fire_at - -func _init(topBoard): - hits = topBoard - func _on_Fire_pressed(): var crosshair = get_node("Crosshair") # Check if the crosshair is in a valid position @@ -21,10 +22,7 @@ func _on_Fire_pressed(): var crosshair_pos = crosshair.world_to_board_space(crosshair.position) if(hits[crosshair_pos.x][crosshair_pos.y] == 0): # fires at position - print("Fire at position: ", crosshair_pos) emit_signal("fire_at", crosshair_pos) - # Close the Firing menu - queue_free() return #if invalid position popup appears var dialog = get_node("FireDialog") @@ -32,7 +30,7 @@ func _on_Fire_pressed(): func _on_FireDialog_confirmed(): get_node("Crosshair").visible = true - + const OFFSET = Vector2(18, 18) func texture(index): @@ -52,7 +50,4 @@ func texture(index): var sprite = Sprite.new() sprite.texture = t sprite.position = Vector2(index.x, index.y) * textureSize + OFFSET - - printt(t.get_height(), t.get_width()) - $board_blue.add_child(sprite) diff --git a/godot_ship/script/game/Gameplay/Game.gd b/godot_ship/script/game/Gameplay/Game.gd index e16cd43..4da38cf 100644 --- a/godot_ship/script/game/Gameplay/Game.gd +++ b/godot_ship/script/game/Gameplay/Game.gd @@ -1,11 +1,18 @@ extends Control # warning-ignore-all:unused_signal +# warning-ignore-all:return_value_discarded + +enum {MISS = -1, READY = 0, HIT = 1, SUNK = 2, LOST = 3} # Signals signal fire # fire(position) -signal hit # hit (state: see Miss/Ready/Hit/Sunk enum in Board.gd) -signal win # win (): sent when opponent player lost +signal hit # hit (state): see Miss/Ready/Hit/Sunk enum in Board.gd) +signal miss +signal loss +signal forfeit + +signal game_ready # Path to Player class, for instantiating new Players in code var Player = preload("res://scenes/Game/Player.tscn") @@ -16,10 +23,6 @@ var Victory = preload("res://scenes/Game/Victory.tscn") # Array of instances of the Player class; stores the Players var player var players_ready = [] -# turn counter -var turn = 0 -# winner -var winner = 0 # Every game is a multiplayer game, even the ones that aren't. # We're taking the Minecraft approach, baby @@ -28,129 +31,159 @@ var network_id # Called when the node enters the scene tree for the first time. func _ready(): - get_node("ConfirmationDialog").get_ok().text = "Yes" - get_node("ConfirmationDialog").get_cancel().text = "No" - get_node("ConfirmationDialog").get_ok().rect_min_size.x = 100 - get_node("ConfirmationDialog").get_cancel().rect_min_size.x = 100 - if multiplayer: - # TODO: Spawn a lobby where people can either connect to a peer or create a server + get_node("Forfeit Confirmation").get_ok().text = "Yes" + get_node("Forfeit Confirmation").get_cancel().text = "No" + get_node("Forfeit Confirmation").get_ok().rect_min_size.x = 100 + get_node("Forfeit Confirmation").get_cancel().rect_min_size.x = 100 + + if Net.connected: + Net.connect("disconnected", self, "connection_error") + Net.connect("incoming", self, "_on_Net_incoming") pass game_setup() # Function used to keep track of which players are ready -# TODO: Change this to keep track of ready states only -func player_ready(): - players_ready.append(Net.get_network_id()) - pass +func player_ready(sender): + print("player_ready(%s), %d" % [sender, players_ready.size()]) + players_ready.append(sender) + if (players_ready.size() >= Net.peer_info.size()): + emit_signal("game_ready") # Member functions: -# game_start: starts the game +# game_setup: starts the game sync func game_setup(): # If there's no server connected, create one if not Net.connected: # TODO: Create a fake peer who we can automate, for single-player mode Net.start_host() network_id = Net.get_network_id() + player = Player.instance() + player.connect("player_ready", self, "_on_player_ready") + add_child(player) + player.set_up_begin() + yield(self, "game_ready") + if Net.hosting: + state_fire() + +# state_fire: The firing state. Displays fire menu, then notifies opponent. +remote func state_fire(): + var pos = player.turn_start() + if pos is GDScriptFunctionState: + pos = yield(pos, "completed") + rpc("state_check", pos) + +# state_check: The checking state. Branches out to the other states. +# pos: Position which the opponent is trying to fire upon +remote func state_check(pos): + var res = player.hit(pos) + # Tell the opponent + Net.send(0, ["hit", res], Net.REPLY) + rpc("play_hit_sound", res) + match res: + LOST: + # the other player wins + rpc("state_win", player.board.ship_data) + victory_screen(null, false) + SUNK, HIT: + # Hit + rpc("state_fire") + MISS: + # Our turn to fire + state_fire() pass -# game_start: Runs on host. Controls the game. -func game_start(): - var state = "P1_fire" - # Make sure we're the server - while true: - match state: - "P1_fire": - # Tell local player to fire - - # Wait for result - - # Send fire REQUEST to P2 - pass - "P2_check": - # Wait for hit - var ret = yield(self, "hit") - # Record the hit - - # - pass - "P2_fire": - pass - "P1_check": - # Check if - pass - "P1_win": - pass - "P2_win": - pass +# state_win: The winning state. If you reach here, someone's won. +# ships: The opponent's ship data, so that their board can be shown +remote func state_win(ships): + victory_screen(ships) pass -func fire_on(id, pos:Vector2): - # REQUEST fire on opponent - Net.send(id, ["fire", pos], Net.REQUEST) - # Wait for REPLY +# play_hit_sound: Play a hit sound depending on the severity of the hit +# value: Lost/Sunk/Hit/Miss +sync func play_hit_sound(value): + match value: + LOST, SUNK: + AudioBus.emit_signal("ship_sunk") + HIT: + AudioBus.emit_signal("ship_hit") + MISS: + AudioBus.emit_signal("ship_missed") -func return_hit(id, ship_status): +# hit: Update the local player's board when the opponent fires +# pos: Opponent's target +func hit(pos): + pos = Vector2(pos[0], pos[1]) + var res = player.hit(pos) + return res - Net.send(id, ["hit", ship_status], Net.REPLY) - -func _on_win(): - pass +# mark: Update the local player's hit/miss board when opponent replies +func mark(res): + return player.mark(res) +# _on_Net_incoming: Handle mail. func _on_Net_incoming(mail): + print ("mail: ", mail, mail.size()) if mail.size() == 3: - var sender = mail[0] + print ("mail: ", mail, mail.size()) + var sender = int(mail[0]) var message = mail[1] - var mailtype = mail[2] + var mailtype = int(mail[2]) + printt(sender, message, mailtype) match mailtype: - # if message is a REQUEST (to perform an action) - Net.REQUEST: - match message[0]: - # Opponent asks for player.fire() - "fire": - emit_signal("fire", message[1]) - # Opponent asks for hit(pos) - "hit": - pass - _: - pass Net.REPLY: + print ("got REPLY") # message is a REPLY (return value) match message[0]: + # on "fire": fire(result) "fire": - emit_signal("hit", message[1]) - # Return value of + hit(message[1]) + # on "hit": mark(state) "hit": + mark(message[1]) + "forfeit": pass - pass Net.READY: + print ("got READY") # Add player to the ready array - players_ready.append(sender) - pass + player_ready(sender) + _: + print ("got ", mailtype) # _on_player_ready: Player Ready signal handler func _on_player_ready(): print ("_on_player_ready") - Net.send(1, [], Net.READY) + Net.send(0, [], Net.READY) + player_ready(Net.get_network_id()) # victory_screen: display the victory screen -func victory_screen(): - # TODO: Create the victory screen, fill it with knowledge - pass - -# display_turn: display which turn it is on the screen -func display_turn(): - # TODO: Update the turn display, if there is one? - pass +func victory_screen(ships, winner = true): + if winner: + # Hide the buttons + get_node("Bittons").hide() + # Create a new Victory screen + var victory = Victory.instance() + # Give it the ships received from the opponent + victory.reveal_ships(ships) + # Print a nice message to stdout + print("You won!") + # Add victory to the scene tree + add_child(victory) + else: + end() # _on_Forfeit_pressed: Handle forfeit button press func _on_Forfeit_pressed(): AudioBus.emit_signal("button_clicked") - get_node("ConfirmationDialog").popup() + get_node("Forfeit Confirmation").popup_centered() # end: end the Game -func end(): +sync func end(): queue_free() + +func connection_error(): + get_node("Connection Error").popup_centered() + # _on_Button_button_down: Handle win button press # TODO: This isn't a thing any more func _on_Button_button_down(): @@ -159,6 +192,13 @@ func _on_Button_button_down(): add_child(victory) victory.connect("exit_main", self, "end") -func _on_ConfirmationDialog_confirmed(): +func _on_Forfeit_Confirmation_confirmed(): + if Net.connected: + # Send forfeit request to all users + rpc("end") end() +func _on_Connection_Error_confirmed(): + # End the game + queue_free() + diff --git a/godot_ship/script/game/Gameplay/Player.gd b/godot_ship/script/game/Gameplay/Player.gd index 4fc6074..e3cb28e 100644 --- a/godot_ship/script/game/Gameplay/Player.gd +++ b/godot_ship/script/game/Gameplay/Player.gd @@ -12,15 +12,13 @@ var Setup = preload("res://scenes/Game/Setup.tscn") var Fire = preload("res://scenes/Game/Fire.tscn") # Members -var pid # Player ID var board # Board - -var fire_at_position # Position to fire at +var fire_pos = Vector2(-1,-1) +var target = Vector2(-1,-1) # Called when the node enters the scene tree for the first time. func _ready(): - # Set the player ID according to which network peer ID we are - pid = int(name) + pass func set_up_begin(): var setup = Setup.instance() @@ -32,22 +30,23 @@ func set_up_begin(): # hit: Called when opponent fires on us. # Update internal state, and return hit/miss/sunk func hit(pos): + target = pos var res = board.hit(pos) return res # mark: Called when the opponent returns hit/miss/sunk # Update internal state, return ack/nak -func mark(pos, value): +func mark(value): # Mark the position on the top board - board.fire(pos, value) + return board.fire(fire_pos, value) # place_ship: called when ships are placed. # forwards Ship locations to the Board, so that it may construct a ship # ship: a list of ship properties {position, orientation, size, variant} func place_ship(pos, size, orientation, variant): - board.place_ship(pos, size, orientation, variant) + return board.place_ship(pos, size, orientation, variant) -# setup: set up the board given the placed ship locations +# set_up: set up the board given the placed ship locations # Places each ship onto the board # ships: a list of lists of ship properties [[position, orientation, size, variant], ...] func set_up(ships): @@ -62,17 +61,22 @@ func set_up(ships): # Initiates the player's turn, and blocks until the player selects a location to fire upon # returns: fire = [player id, target coordinates] func turn_start(): - print("turn_start") var fire = Fire.instance() - + fire.hits = board.top_board add_child(fire) - var pos = yield(fire, "fire_at") - return pos + fire_pos = yield(fire, "fire_at") + fire.queue_free() + return fire_pos + # getBoard: returns the player's board # returns: board -func getBoard(): - return board +func board_query(boardname): + match boardname: + "top": + return board.query_top (fire_pos) + "bottom": + return board.quert_bottom (target) # forfeit: ends game for player # Sinks all ships @@ -86,7 +90,3 @@ func forfeit(): # getShipCount: get the number of ships the player has left alive func getShipCount(): return board.get_ship_count() - - -func _on_fire_at(pos): - fire_at_position = pos diff --git a/godot_ship/script/game/Gameplay/Ship.gd b/godot_ship/script/game/Gameplay/Ship.gd index bddc046..c154608 100644 --- a/godot_ship/script/game/Gameplay/Ship.gd +++ b/godot_ship/script/game/Gameplay/Ship.gd @@ -59,6 +59,8 @@ func hit(pos): # Sink the ship. set_sunk() res = SUNK + # Update graphics + update() return res # update: (re)calculates extents and textures diff --git a/godot_ship/script/game/Victory.gd b/godot_ship/script/game/Victory.gd index 5d95329..dcf0b43 100644 --- a/godot_ship/script/game/Victory.gd +++ b/godot_ship/script/game/Victory.gd @@ -1,15 +1,18 @@ extends Control -signal exit_main -# Declare member variables here. Examples: -# var a = 2 -# var b = "text" - +# Path to Board class, for instantiating new Boards in code +var Board = preload("res://scenes/Game/Board.tscn") # Called when the node enters the scene tree for the first time. func _ready(): pass # Replace with function body. +# Reveal a list of ships +func reveal_ships(ships:Array): + var board = Board.instance() + add_child(board); + for ship in ships: + board.callv("place_ship", ship) # Called every frame. 'delta' is the elapsed time since the previous frame. #func _process(delta): @@ -17,11 +20,11 @@ func _ready(): func _on_restart_button_down(): AudioBus.emit_signal("button_clicked") - #MessageBus.emit_signal("change_scene", "Multiplayer") - pass # Replace with function body. + MessageBus.emit_signal("change_scene", "Multiplayer") + MessageBus.emit_signal("kill_scene", "Game") + # returns player(s) back to main menu func _on_exit_to_main_button_down(): AudioBus.emit_signal("button_clicked") - #MessageBus.emit_signal("change_scene", "Title") - emit_signal("exit_main") + MessageBus.emit_signal("return_to_title") diff --git a/godot_ship/script/network/Lobby.gd b/godot_ship/script/network/Lobby.gd index 28f915b..6464d0e 100644 --- a/godot_ship/script/network/Lobby.gd +++ b/godot_ship/script/network/Lobby.gd @@ -1,8 +1,10 @@ extends Control # Ignore discarded return values -# warning-ignore:return_value_discarded +# warning-ignore-all:return_value_discarded onready var player_list = find_node("Player List") -onready var ip = find_node("IP Address") +onready var ip_address = find_node("IP Address") +onready var name_popup = find_node("Change Name") +onready var game_popup = find_node("Connect to Game") # TODO: Write a function to update Player List with the list of attached players @@ -17,28 +19,33 @@ func _on_peers_updated(): func set_IP_Address_text(show): # Print the IP address and port if show: - ip.text = "IP: %s\nPort: %s" % [Net.get_ip(), Net.DEFAULT_PORT] + ip_address.text = "IP: %s\nPort: %s" % [Net.get_ip(), Net.DEFAULT_PORT] else: - ip.text = "" + ip_address.text = "" func _ready(): Net.connect("peers_updated", self, "_on_peers_updated") Net.connect("disconnected", self, "_on_Net_disconnected") + name_popup.get_node("Name Entry").text = Net.get_hostname() _on_peers_updated() pass -func show_Connected_Options(show): - # Hide the host and connect buttons +func show_Connected_Options(show, host = false): + # [Hide]/Show the host options + get_node("Lobby Options/Connected Options/Host Options").visible = host + # [Hide]/Show the host and connect buttons get_node("Lobby Options/Host or Connect").visible = !show - # Show the host options + # [Show]/Hide the host options get_node("Lobby Options/Connected Options").visible = show # Buttons # Host Button: Host a game # Hides the connect button func _on_Host_Button_pressed(): + # Make noise + AudioBus.emit_signal("button_clicked") # Show "Connected Options" - show_Connected_Options(true) + show_Connected_Options(true, true) # Show the host IP address set_IP_Address_text(true) # Begin hosting @@ -48,6 +55,8 @@ func _on_Host_Button_pressed(): # Disconnect from (or stop hosting) a game # Shows the host/connect buttons func _on_Disconnect_Button_pressed(): + # Make noise + AudioBus.emit_signal("button_clicked") # Disconnect Net.disconnect_host() # Hide "Connected Options" @@ -55,6 +64,13 @@ func _on_Disconnect_Button_pressed(): # Hide the host IP address set_IP_Address_text(false) +func _on_Start_Game_pressed(): + # If there are enough players for a game + if Net.peer_info.size() >= 2: + # Start the game for all players + rpc("start_game") + pass # Replace with function body. + func _on_Net_disconnected(): # Hide "Connected Options" show_Connected_Options(false) @@ -62,28 +78,20 @@ func _on_Net_disconnected(): set_IP_Address_text(false) func _on_Change_Name_Button_pressed(): + # Make noise + AudioBus.emit_signal("button_clicked") # Show the Change Name dialogue get_node("Change Name").popup_centered() - pass func _on_Connect_Button_pressed(): + # Make noise + AudioBus.emit_signal("button_clicked") # Show the Connect to Game dialogue get_node("Connect to Game").popup_centered() - pass - -func _on_Connect_to_Game_confirmed(): - # Get the IP and port specified by the player - var ipbox = find_node("IP and Port Entry") - # Split it into IP and Port segments - var ip_port = ipbox.text.split(":") - # If text exists and contains valid IP address - if ip_port.size() > 0 and ip_port[0].is_valid_ip_address(): - # Connect to host - Net.callv("connect_host", ip_port) - # Show "Connected Options" - show_Connected_Options(true) func _on_Exit_Lobby_pressed(): + # Make noise + AudioBus.emit_signal("button_clicked") # Disconnect if Net.connected: Net.disconnect_host() @@ -92,6 +100,8 @@ func _on_Exit_Lobby_pressed(): func _on_IP_and_Port_Entry_text_entered(text): + # Make noise + AudioBus.emit_signal("button_clicked") # Split it into IP and Port segments var ip_port = text.split(":") # If text exists and contains valid IP address @@ -102,11 +112,21 @@ func _on_IP_and_Port_Entry_text_entered(text): # Show "Connected Options" show_Connected_Options(true) # Hide the popup - find_node("Connect to Game").hide() + game_popup.hide() func _on_Name_Entry_text_entered(text): - # Change the name - Net.change_name(text) - # Hide the popup - find_node("Change Name").hide() + # Make noise + AudioBus.emit_signal("button_clicked") + # Check the length of the name + if text.length() < 18: + # Change the name + Net.change_name(text) + # Hide the popup + name_popup.hide() + +sync func start_game(): + MessageBus.emit_signal("change_scene", "Gameplay") + queue_free() + + diff --git a/godot_ship/script/network/Net.gd b/godot_ship/script/network/Net.gd index 6b75b99..3eb3a7a 100644 --- a/godot_ship/script/network/Net.gd +++ b/godot_ship/script/network/Net.gd @@ -8,9 +8,11 @@ const LOCALHOST = "127.0.0.1" # Enums, used for mail types # Mail types: -# 1: REQUEST: Message is a request for information -# 0: REPLY: Message is a reply -enum {REPLY, REQUEST, READY, ACK} +# 0: REQUEST: Message is a request for information +# 1: REPLY: Message is a reply +# 2: READY: Message is "ready" +# 3: ACK: Message is an acknowledgement +enum {REQUEST, REPLY, READY, ACK} # Signals # incoming(mail): Sent when there's an incoming message @@ -36,6 +38,10 @@ var local_info = {"name": ""} # mail: The message received from the sender (implicitly JSON-decoded by JSONRPC) # mail_type: Type of mail (see "Mail Types" enum above) remote func receive(mail): + print_debug("recv: %s" % mail) + # Unpack the mail + # Uses json parser of unknown stability, how fun + mail = parse_json(mail) # Get the sender's ID and force letter to be properly addressed mail[0] = get_tree().get_rpc_sender_id() # Add the mail to the inbox (so it can be read back later if necessary @@ -48,6 +54,7 @@ remote func receive(mail): # mail: Variant of a json-encodable type (non-Object) to send # mail_type: Type of mail (see "Mail Types" enum above) func send(id, mail, mail_type = REPLY): + print_debug("send: %d, %s, %d" % [id, mail, mail_type]) # Make the recipient receive the mail rpc_id(id, "receive", to_json([-1, mail, mail_type])) @@ -81,7 +88,7 @@ func accept_guests(accept:bool): func connect_host(ip = LOCALHOST, port = DEFAULT_PORT): get_hostname() var peer = NetworkedMultiplayerENet.new() - var ret = peer.create_client(ip, port) + var ret = peer.create_client(ip, int(port)) get_tree().network_peer = peer return ret @@ -106,9 +113,10 @@ func disconnect_host(): func change_name(name): # Change name locally local_info["name"] = name - # Send updated info info to all peers - rpc("register_peer", local_info) - pass + # If connected, update peers + if connected: + # Send updated info info to all peers + rpc("register_peer", local_info) # Helper Functions # get_hostname: Asks the host machine to provide its hostname, @@ -130,7 +138,7 @@ func get_ip(): pass func _ready(): - var _trash + var _trash _trash = get_tree().connect("network_peer_connected", self, "_peer_connected" ) _trash = get_tree().connect("network_peer_disconnected", self, "_peer_disconnected") _trash = get_tree().connect("connected_to_server", self, "_host_connected" ) diff --git a/godot_ship/script/title screen/Title Screen.gd b/godot_ship/script/title screen/Title Screen.gd index 4111b75..0f0fbb8 100644 --- a/godot_ship/script/title screen/Title Screen.gd +++ b/godot_ship/script/title screen/Title Screen.gd @@ -12,7 +12,7 @@ func _ready(): func _on_Singleplayer_pressed(): AudioBus.emit_signal("button_clicked") - MessageBus.emit_signal("change_scene", "Singleplayer") + MessageBus.emit_signal("change_scene", "Gameplay") queue_free() func _on_Multiplayer_pressed():