diff options
| author | Daniel Weipert <code@drogueronin.de> | 2021-01-02 14:54:57 +0100 | 
|---|---|---|
| committer | Daniel Weipert <code@drogueronin.de> | 2021-01-02 14:54:57 +0100 | 
| commit | ebae6d04ffc95c6648e863d3de71835f6cd4be96 (patch) | |
| tree | 58ce9119a65ccd6925d661f12aab98a057dfb53d | |
| parent | fb64f15e22acfc1c03c7c5357dd66077454adbcf (diff) | |
Initial working commit
| -rw-r--r-- | Character.tscn | 12 | ||||
| -rw-r--r-- | Global.gd | 56 | ||||
| -rw-r--r-- | Levels/Level_0001.tscn | 7 | ||||
| -rw-r--r-- | Network/Lobby.gd | 82 | ||||
| -rw-r--r-- | Network/Lobby.tscn | 101 | ||||
| -rw-r--r-- | Network/Network.gd | 114 | ||||
| -rw-r--r-- | Objects/Flag.tscn | 1 | ||||
| -rw-r--r-- | UI/LevelSelect.gd | 6 | ||||
| -rw-r--r-- | UI/LevelSelectCell.gd | 7 | ||||
| -rw-r--r-- | UI/LevelSelectCell.tscn | 12 | ||||
| -rw-r--r-- | project.godot | 11 | 
11 files changed, 393 insertions, 16 deletions
| diff --git a/Character.tscn b/Character.tscn index 5902649..eb0b6b6 100644 --- a/Character.tscn +++ b/Character.tscn @@ -14,6 +14,11 @@  [sub_resource type="SpriteFrames" id=1]  animations = [ { +"frames": [ ExtResource( 8 ) ], +"loop": true, +"name": "slide", +"speed": 5.0 +}, {  "frames": [ ExtResource( 4 ) ],  "loop": true,  "name": "back", @@ -24,11 +29,6 @@ animations = [ {  "name": "idle",  "speed": 5.0  }, { -"frames": [ ExtResource( 8 ) ], -"loop": true, -"name": "slide", -"speed": 5.0 -}, {  "frames": [ ExtResource( 5 ), ExtResource( 6 ) ],  "loop": true,  "name": "walk", @@ -64,6 +64,7 @@ animations = [ {  extents = Vector2( 9.21901, 11.2317 )  [node name="Character" type="KinematicBody2D"] +collision_mask = 15  script = ExtResource( 1 )  [node name="Sprite" type="AnimatedSprite" parent="."] @@ -81,4 +82,3 @@ cast_to = Vector2( 0, 150 )  [node name="CheckFallLanding" type="RayCast2D" parent="."]  enabled = true -cast_to = Vector2( 0, 50 ) @@ -1,6 +1,10 @@  extends Node +signal level_map_updated() +signal game_won() + +  const Levels = [  	"Level_0001",  	"Level_0001", @@ -20,7 +24,10 @@ func _ready():  	for level in self.Levels:  		self.Level_Map.push_back({  			time = 0, -			cleared_by = -1, +			cleared_by = { # Network.player +				idx = -1, +				name = "" +			},  			meta = {  				path = "res://Levels/%s.tscn" % level,  				name = level, @@ -55,6 +62,51 @@ func end_level(instance_level):  	var time = stepify(instance_level.timer, 0.01)  	if (global_level.time == 0 or time < global_level.time):  		global_level.time = time -		global_level.cleared_by = randi() & 1 +		global_level.cleared_by = Network.player +	for id in Network.players: +		rpc_id(id, "_update_level_map", instance_level.idx, global_level)  	get_tree().change_scene("res://UI/LevelSelect.tscn") +	 +	self.check_win() + + +remote func _update_level_map(idx, global_level): +	self.Level_Map[idx] = global_level +	emit_signal("level_map_updated") + + +func check_win(): +	var has_won = false +	 +	var cleared_levels_idx = [] +	for idx in range(self.Level_Map.size()): +		if self.Level_Map[idx].cleared_by.idx == Network.player.idx: +			cleared_levels_idx.push_back(idx) +	 +	var possible_winning_conditions = [ +		[0, 1, 2], +		[3, 4, 5], +		[6, 7, 8], +		 +		[0, 3, 6], +		[1, 4, 7], +		[2, 5, 8], +		 +		[0, 4, 8], +		[2, 4, 6], +	] +	 +	# because there's no intersection method on arrays.. +	for cond in possible_winning_conditions: +		var has_cleared = 0 +		for digit in cond: +			if digit in cleared_levels_idx: +				has_cleared += 1 +		 +		if has_cleared == 3: +			has_won = true +			break +	 +	if has_won: +		emit_signal("game_won", Network.player) diff --git a/Levels/Level_0001.tscn b/Levels/Level_0001.tscn index bbae830..89dba41 100644 --- a/Levels/Level_0001.tscn +++ b/Levels/Level_0001.tscn @@ -7,21 +7,22 @@  [node name="Level_0001" type="Node2D"]  script = ExtResource( 4 ) -startingPosition = Vector2( 144.471, 115.947 ) -cameraLimitRight = 700 -cameraLimitBottom = 500  [node name="TileMap" type="TileMap" parent="."]  tile_set = ExtResource( 1 )  cell_size = Vector2( 16, 16 ) +collision_layer = 2 +collision_mask = 15  format = 1  tile_data = PoolIntArray( 327692, 0, 6, 327693, 0, 8, 393228, 0, 65542, 393229, 0, 65545, 458764, 0, 65542, 458765, 0, 65545, 524295, 0, 0, 524296, 0, 1, 524297, 0, 1, 524298, 0, 1, 524299, 0, 1, 524300, 0, 65542, 524301, 0, 65545, 524302, 0, 1, 524303, 0, 1, 524304, 0, 1, 524305, 0, 1, 524306, 0, 1, 524307, 0, 2, 589836, 0, 131078, 589837, 0, 131080, 720918, 0, 0, 720919, 0, 1, 720920, 0, 1, 720921, 0, 1, 720922, 0, 1, 720923, 0, 1, 720924, 0, 1, 720925, 0, 1, 720926, 0, 1, 720927, 0, 1, 720928, 0, 1, 720929, 0, 1, 720930, 0, 1, 720931, 0, 1, 720932, 0, 1, 720933, 0, 1, 720934, 0, 1, 720935, 0, 1, 720936, 0, 1, 720937, 0, 2, 917518, 0, 6, 917519, 0, 8, 917523, 0, 6, 917524, 0, 8, 983054, 0, 65542, 983055, 0, 65545, 983059, 0, 65542, 983060, 0, 65545, 1048590, 0, 65542, 1048591, 0, 65545, 1048595, 0, 65542, 1048596, 0, 65545, 1114126, 0, 65542, 1114127, 0, 65545, 1114131, 0, 65542, 1114132, 0, 65545, 1179662, 0, 65542, 1179663, 0, 65545, 1179667, 0, 65542, 1179668, 0, 65545, 1245198, 0, 65542, 1245199, 0, 65545, 1245203, 0, 65542, 1245204, 0, 65545, 1310734, 0, 65542, 1310735, 0, 65545, 1310739, 0, 65542, 1310740, 0, 65545, 1376270, 0, 65542, 1376271, 0, 65545, 1376275, 0, 65542, 1376276, 0, 65545, 1441806, 0, 65542, 1441807, 0, 65545, 1441811, 0, 65542, 1441812, 0, 65545, 1507342, 0, 65542, 1507343, 0, 65545, 1507347, 0, 65542, 1507348, 0, 65545, 1572878, 0, 65542, 1572879, 0, 65545, 1572883, 0, 65542, 1572884, 0, 65545, 1638414, 0, 65542, 1638415, 0, 65545, 1638419, 0, 65542, 1638420, 0, 65545, 1703950, 0, 131078, 1703951, 0, 131080, 1703955, 0, 131078, 1703956, 0, 131080, 1900544, 0, 0, 1900545, 0, 1, 1900546, 0, 1, 1900547, 0, 1, 1900548, 0, 1, 1900549, 0, 1, 1900550, 0, 1, 1900551, 0, 1, 1900552, 0, 1, 1900553, 0, 1, 1900554, 0, 1, 1900555, 0, 1, 1900556, 0, 1, 1900557, 0, 1, 1900558, 0, 1, 1900559, 0, 1, 1900560, 0, 1, 1900561, 0, 1, 1900562, 0, 1, 1900563, 0, 1, 1900564, 0, 1, 1900565, 0, 2 )  [node name="Flag" parent="." instance=ExtResource( 3 )]  position = Vector2( 602.469, 111.673 ) +collision_layer = 0  [node name="Character" parent="." instance=ExtResource( 2 )]  position = Vector2( 144.471, 115.947 ) +collision_mask = 15  [node name="Camera2D" type="Camera2D" parent="Character"]  current = true diff --git a/Network/Lobby.gd b/Network/Lobby.gd new file mode 100644 index 0000000..d962081 --- /dev/null +++ b/Network/Lobby.gd @@ -0,0 +1,82 @@ +extends Control + + +func _ready(): +	Network.connect("connection_succeeded", self, "_on_connection_succeeded") +	Network.connect("connection_failed", self, "_on_connection_failed") +	Network.connect("player_list_changed", self, "refresh_lobby") +	Network.connect("game_error", self, "_on_game_error") +	Network.connect("game_ended", self, "_on_game_ended") +	 +	if OS.has_environment("USERNAME"): +		$Connect/Name.text = OS.get_environment("USERNAME") +	else: +		var desktop_path = OS.get_system_dir(0).replace("\\", "/").split("/") +		$Connect/Name.text = desktop_path[desktop_path.size() - 2] + + +func disable_connect_buttons(is_disabled = true): +	$Connect/Host.disabled = is_disabled +	$Connect/Join.disabled = is_disabled + + +func refresh_lobby(): +	var players = Network.players.values() +	var player = Network.player +	 +	$Players/List.clear() +	$Players/List.add_item(player.name + " (You)") +	for p in players: +		$Players/List.add_item(p.name) +	 +	$Players/Start.disabled = not get_tree().is_network_server() + + +func _on_connection_succeeded(): +	$Connect.hide() +	$Players.show() + + +func _on_connection_failed(): +	self.disable_connect_buttons() +	$Connect/Error.set_text("Connection failed!") + + +func _on_game_error(error): +	$ErrorDialog.dialog_text = error +	$ErrorDialog.popup_centered_minsize() +	self.disable_connect_buttons() + + +func _on_game_ended(): +	self.show() +	$Connect.show() +	$Players.hide() +	self.disable_connect_buttons() + + +func _on_Host_pressed(): +	$Connect.hide() +	$Players.show() +	$Connect/Error.text = "" +	 +	var player_name = $Connect/Name.text +	Network.host_game(player_name) +	self.refresh_lobby() + + +func _on_Join_pressed(): +	var ip = $Connect/IP.text +	if not ip.is_valid_ip_address(): +		$Connect/Error.text = "Invalid IP address!" +		return +	 +	$Connect/Error.text = "" +	self.disable_connect_buttons(false) +	 +	var player_name = $Connect/Name.text +	Network.join_game(ip, player_name) + + +func _on_Start_pressed(): +	Network.start_game() diff --git a/Network/Lobby.tscn b/Network/Lobby.tscn new file mode 100644 index 0000000..0caf892 --- /dev/null +++ b/Network/Lobby.tscn @@ -0,0 +1,101 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Network/Lobby.gd" type="Script" id=1] + +[node name="Lobby" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 ) +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Connect" type="Panel" parent="."] +margin_left = 424.0 +margin_top = 232.0 +margin_right = 600.0 +margin_bottom = 376.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Name" type="LineEdit" parent="Connect"] +margin_left = 8.0 +margin_top = 8.0 +margin_right = 168.0 +margin_bottom = 32.0 +placeholder_text = "Name" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="IP" type="LineEdit" parent="Connect"] +margin_left = 8.0 +margin_top = 40.0 +margin_right = 168.0 +margin_bottom = 64.0 +placeholder_text = "IP" + +[node name="Host" type="Button" parent="Connect"] +margin_left = 8.0 +margin_top = 112.0 +margin_right = 64.0 +margin_bottom = 136.0 +text = "Host" + +[node name="Join" type="Button" parent="Connect"] +margin_left = 112.0 +margin_top = 112.0 +margin_right = 168.0 +margin_bottom = 136.0 +text = "Join" + +[node name="Error" type="Label" parent="Connect"] +margin_left = 8.0 +margin_top = 72.0 +margin_right = 168.0 +margin_bottom = 104.0 +custom_colors/font_color = Color( 1, 0.137255, 0.137255, 1 ) + +[node name="Players" type="Panel" parent="."] +visible = false +margin_left = 384.0 +margin_top = 48.0 +margin_right = 640.0 +margin_bottom = 512.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Label" type="Label" parent="Players"] +margin_left = 16.0 +margin_top = 16.0 +margin_right = 240.0 +margin_bottom = 32.0 +text = "Lobby" + +[node name="List" type="ItemList" parent="Players"] +margin_left = 16.0 +margin_top = 48.0 +margin_right = 240.0 +margin_bottom = 400.0 +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="Start" type="Button" parent="Players"] +margin_left = 64.0 +margin_top = 416.0 +margin_right = 192.0 +margin_bottom = 448.0 +text = "START!" +__meta__ = { +"_edit_use_anchors_": false +} + +[node name="ErrorDialog" type="AcceptDialog" parent="."] +margin_right = 83.0 +margin_bottom = 58.0 +[connection signal="pressed" from="Connect/Host" to="." method="_on_Host_pressed"] +[connection signal="pressed" from="Connect/Join" to="." method="_on_Join_pressed"] +[connection signal="pressed" from="Players/Start" to="." method="_on_Start_pressed"] diff --git a/Network/Network.gd b/Network/Network.gd new file mode 100644 index 0000000..0f007b4 --- /dev/null +++ b/Network/Network.gd @@ -0,0 +1,114 @@ +extends Node + + +signal connection_succeeded() +signal connection_failed() +signal player_list_changed() +signal game_error() +signal game_ended() + + +const PORT = 10567 + +const MAX_PEERS = 2 + + +var peer = null + +var player = { +	idx = 0, +	name = "", +} + +# Dictionary { id = { idx: 1, name: "" } } +var players = {} +var players_ready = [] + + +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, "_connection_succeeded") +	get_tree().connect("connection_failed", self, "_connection_failed") +	get_tree().connect("server_disconnected", self, "_server_disconnected") +	Global.connect("game_won", self, "end_game") + + +remote func register_player(name): +	var id = get_tree().get_rpc_sender_id() +	self.players[id] = { +		name = name +	} +	emit_signal("player_list_changed") + + +func unregister_player(id): +	self.player.erase(id) +	emit_signal("player_list_changed") + + +func host_game(player_name): +	self.player.name = player_name +	self.peer = NetworkedMultiplayerENet.new() +	self.peer.create_server(self.PORT, self.MAX_PEERS) +	get_tree().set_network_peer(self.peer) + + +func join_game(ip, player_name): +	self.player.name = player_name +	self.peer = NetworkedMultiplayerENet.new() +	self.peer.create_client(ip, self.PORT) +	get_tree().set_network_peer(self.peer) + + +func start_game(): +	# preconfigure game and set idx to each player +	var idx = 1 +	for id in self.players: +		self.players[id].idx = idx +		rpc_id(id, "_preconfigure_game", idx) +		idx += 1 +	 +	# start game for everyone +	rpc("_start_game") + + +remote func _preconfigure_game(idx): +	self.player.idx = idx +	 + +sync func _start_game(): +	get_tree().change_scene("res://UI/LevelSelect.tscn") + + +func end_game(winning_player): +	# TODO: change scene for all to win scene and set winning player id, +	# so it can be displayed with self.players +	print(winning_player) +	get_tree().change_scene("res://Network/Lobby.tscn") +	pass + + +func _player_connected(id): +	rpc_id(id, "register_player", self.player.name) + + +func _player_disconnected(id): +	# if game is in progress: +		# self.end_game() ? +	# else +		self.unregister_player(id) + + +func _connection_succeeded(): +	emit_signal("connection_succeeded") + + +func _connection_failed(): +	get_tree().set_network_peer(null) # remove peer +	emit_signal("connection_failed") + + +func _server_disconnected(): +	emit_signal("game_error", "Server disconnected!") +	self.end_game("") diff --git a/Objects/Flag.tscn b/Objects/Flag.tscn index 0cc1c35..e2c44eb 100644 --- a/Objects/Flag.tscn +++ b/Objects/Flag.tscn @@ -7,6 +7,7 @@  extents = Vector2( 64.2993, 64.1957 )  [node name="Flag" type="Area2D"] +collision_layer = 0  script = ExtResource( 2 )  [node name="Sprite" type="Sprite" parent="."] diff --git a/UI/LevelSelect.gd b/UI/LevelSelect.gd index c173a7b..7abc5f2 100644 --- a/UI/LevelSelect.gd +++ b/UI/LevelSelect.gd @@ -2,10 +2,14 @@ extends Control  func _ready(): +	Global.connect("level_map_updated", self, "draw") +	draw() + + +func draw():  	var Cell = load("res://UI/LevelSelectCell.tscn")  	for idx in range(9): -		var level = Global.get_level(idx)  		var cell = Cell.instance()  		cell.level_idx = idx  		cell.set_rect_size(1024/3, 600/3) diff --git a/UI/LevelSelectCell.gd b/UI/LevelSelectCell.gd index 1bd1366..16ff961 100644 --- a/UI/LevelSelectCell.gd +++ b/UI/LevelSelectCell.gd @@ -8,12 +8,13 @@ func _ready():  	var level = Global.get_level(self.level_idx)  	$ClearMark.text = "" -	if level.cleared_by == Enum.PLAYER.FIRST: +	if level.cleared_by.idx == Enum.PLAYER.FIRST:  		$ClearMark.text = "X" -	elif level.cleared_by == Enum.PLAYER.SECOND: +	elif level.cleared_by.idx == Enum.PLAYER.SECOND:  		$ClearMark.text = "O" -	$Time.text = String(level.time) + "s" +	$Time.text = str(level.time) + "s" +	$Name.text = level.cleared_by.name  func set_rect_size(x, y): diff --git a/UI/LevelSelectCell.tscn b/UI/LevelSelectCell.tscn index 968e913..3660cef 100644 --- a/UI/LevelSelectCell.tscn +++ b/UI/LevelSelectCell.tscn @@ -56,3 +56,15 @@ valign = 1  __meta__ = {  "_edit_use_anchors_": false  } + +[node name="Name" type="Label" parent="."] +margin_left = 8.0 +margin_top = 176.0 +margin_right = 66.0 +margin_bottom = 197.0 +custom_fonts/font = SubResource( 3 ) +text = "Player" +valign = 1 +__meta__ = { +"_edit_use_anchors_": false +} diff --git a/project.godot b/project.godot index 19ec07a..c47face 100644 --- a/project.godot +++ b/project.godot @@ -16,12 +16,14 @@ _global_script_class_icons={  [application]  config/name="TicTacTux" +run/main_scene="res://Network/Lobby.tscn"  config/icon="res://icon.png"  [autoload] -Global="*res://Global.gd"  Enum="*res://Enum.gd" +Global="*res://Global.gd" +Network="*res://Network/Network.gd"  [input] @@ -41,6 +43,13 @@ ui_up={   ]  } +[layer_names] + +2d_physics/layer_1="Player" +2d_physics/layer_2="Platform" +2d_physics/layer_3="Object" +2d_physics/layer_4="Enemy" +  [rendering]  environment/default_environment="res://default_env.tres" | 
