From 5b05771bb358b28485a640bc8f5030b9d2627c08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ensar=20Saraj=C4=8Di=C4=87?= Date: Fri, 21 Jan 2022 13:50:50 +0100 Subject: [PATCH] Add track minimap to GUI --- assets/player_icon.png | Bin 0 -> 1204 bytes assets/player_icon.png.import | 35 ++++++++++ network/multiplayer_controller.gd | 54 ++++++++++++++-- scenes/base_track_level.gd | 2 + scenes/components/curved_line_2d.gd | 12 ++++ scenes/components/curved_line_2d.tscn | 6 ++ scenes/track_minimap.gd | 90 ++++++++++++++++++++++++++ scenes/track_minimap.tscn | 37 +++++++++++ scenes/trackgui.gd | 21 ++++++ scenes/trackgui.tscn | 30 ++++++++- scenes/tracks/track.gd | 6 ++ vehicles/vehicle.gd | 4 ++ 12 files changed, 289 insertions(+), 8 deletions(-) create mode 100644 assets/player_icon.png create mode 100644 assets/player_icon.png.import create mode 100644 scenes/components/curved_line_2d.gd create mode 100644 scenes/components/curved_line_2d.tscn create mode 100644 scenes/track_minimap.gd create mode 100644 scenes/track_minimap.tscn diff --git a/assets/player_icon.png b/assets/player_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..c679b88ad9ced0759e0015565e3afa6eb25ddf1c GIT binary patch literal 1204 zcmV;l1WWsgP)>Id|-37O6~f)aX$JLloO=RMqeF4)6)rJ(l&pinGp(NNH{8ejAD zy<=kpCvE}>MOPOhkuY83=TWL99{gsn?sXkwFqPI7u=NYiDymi%o)->pl~t4Xgol+} zA|-qx?9=3c!ndZLwD`^Bti@j@Yq97e*v+1vY#S%rSjlMx;VEHnAzx9N=P_^MOcz&{ zC6CD(M<+^%ARdxb*d$LGzvQCKtg|oB@GVgik0O7SDw;U5h26e@2g>aPC(y2)N6+EdukZ7+AMv)!gU&31ZvwM0ap_1d~$l+V}(K*k}Ll zKkU>1000SaNLh0L04^f{04^f|c%?sf0008(Nkl(P+?L>?bEDS8$nyfj(r&%Tb(|n0V)M zxtt1xf&d7~=kvdBZf-ib*JLt@DwS$>kW_tZz)slN**Qe*kkR@1d2@Pt`Y@NvRoPsn zQn?C;!!PmRlMMZS|3|ys?%+6%007zF-!Gn>ok<%T8^!DEYs%7KFo=4+enyUE-;?1s z&StaCYPDJgZm!j8t#~{x;COFu&s{E;>o`^_l|+)HFKcUSFCK#S0WL2u`;i@LhwKgx z4vH5S7dAWu|5acHWr^%jOFln zf!72=p^ybHV7Xvs9Pa|cZC^DS z4gHVWt*)+ea-#39`Cu?O>2x|J zRu!P#F*y5n5Fo6Lz^neS>M@(mA`qfl@;;w$L9JGIosCALvf4eo03zi zw79tViU;kevzR;34s-YB33hb3*=&;a_4Nv430jU=t=1WyX@|~&b{Gd*8P93pxE;Qc zw0eezhY6T7#j~n_nmxX}yp)~;#P)#WYN(zH<`NSET8;>)0RWL$ET)Bxzn~*a?5HIT zaL*WH*0&B{A>Gl@QOE1`a;T+%x!c;>LQwtvK?Gocy<@pKx(-@$P-R3EMe+~4kk1 PeerInfo: var new_instance = PeerInfo.new() new_instance.id = new_id new_instance.vehicle = new_vehicle new_instance.name = new_name new_instance.spawned = new_spawned + new_instance.color = new_color return new_instance func to_array() -> Array: - return [id, vehicle, name, spawned] + return [id, vehicle, name, spawned, color] func from_array(data: Array) -> void: self.id = data[0] self.vehicle = data[1] self.name = data[2] self.spawned = data[3] + self.color = data[4] func _ready(): @@ -57,9 +70,12 @@ func create_server(port, track, vehicle): current_vehicle = vehicle enet_peer.create_server(port, 2) get_tree().network_peer = enet_peer - peers[1] = PeerInfo.new_peer(1, vehicle, GlobalSettings.multiplayer_name, true) + peers[1] = PeerInfo.new_peer( + 1, vehicle, GlobalSettings.multiplayer_name, true, get_next_color(1) + ) create_player(1, vehicle) get_tree().root.call_deferred("add_child", current_track) + emit_signal("peers_updated") func create_client(address, port, vehicle): @@ -67,18 +83,24 @@ func create_client(address, port, vehicle): enet_peer.create_client(address, port) get_tree().network_peer = enet_peer peers[get_tree().get_network_unique_id()] = PeerInfo.new_peer( - get_tree().get_network_unique_id(), vehicle, GlobalSettings.multiplayer_name, true + get_tree().get_network_unique_id(), + vehicle, + GlobalSettings.multiplayer_name, + true, + get_next_color(1) ) + emit_signal("peers_updated") func _peer_connected(peer_id): - peers[peer_id] = PeerInfo.new_peer(peer_id, "", "", false) + peers[peer_id] = PeerInfo.new_peer(peer_id, "", "", false, get_next_color(peer_id)) rpc_id( peer_id, "add_player", get_tree().get_network_unique_id(), peers[get_tree().get_network_unique_id()].to_array() ) + emit_signal("peers_updated") if get_tree().get_network_unique_id() == 1: rpc_id(peer_id, "select_track", current_track_path) @@ -135,12 +157,12 @@ func quit(): remote func add_player(peer_id, peer_info: Array): if peers[peer_id] == null: - peers[peer_id] = PeerInfo.new_peer(peer_id, "", "", false) + peers[peer_id] = PeerInfo.new_peer(peer_id, "", "", false, get_next_color(peer_id)) if peers[peer_id].spawned == false: peers[peer_id].from_array(peer_info) - # Check for duplicate names on server side + # Check for duplicate names on server side and update colors if get_tree().get_network_unique_id() == 1: var names = [] for peer in peers: @@ -151,11 +173,15 @@ remote func add_player(peer_id, peer_info: Array): peers[peer_id].name = peers[peer_id].name + ("(%s)" % peer_id) rpc("update_name", peer_id, peers[peer_id].name) + peers[peer_id].color = get_next_color(peer_id) + rpc("update_color", peer_id, peers[peer_id].color) + if current_track != null: peers[peer_id].spawned = true create_player(peer_id, peers[peer_id].vehicle) else: peers[peer_id].spawned = false + emit_signal("peers_updated") remote func select_track(track_path): @@ -166,7 +192,21 @@ remote func select_track(track_path): if peers[peer].spawned == false: peers[peer].spawned = true create_player(peer, peers[peer].vehicle) + emit_signal("peers_updated") remote func update_name(peer_id, name: String): peers[peer_id].name = name + emit_signal("peers_updated") + + +remote func update_color(peer_id, color: Color): + peers[peer_id].color = color + emit_signal("peers_updated") + + +func get_next_color(peer_id: int) -> Color: + if peers.size() >= colors.size(): + return Color(peer_id) + else: + return colors[peers.size()] diff --git a/scenes/base_track_level.gd b/scenes/base_track_level.gd index ed546c3..9d6420f 100644 --- a/scenes/base_track_level.gd +++ b/scenes/base_track_level.gd @@ -27,6 +27,7 @@ func spawn_player(player_node: BuggedVehicle, gui: Node) -> void: func spawn_vehicle(vehicle: BuggedVehicle) -> void: + vehicle.connect("position_updated", track, "_on_player_position_updated") reset_player_to(track.get_furthest_checkpoint(), vehicle) add_child(vehicle) @@ -47,6 +48,7 @@ func reset_player_to(node_to_reset_to: Node, player_node: BuggedVehicle) -> void func _spawn_in_player(): reset_player_to(track.get_furthest_checkpoint(), player_node) + player_node.connect("position_updated", track, "_on_player_position_updated") add_child(player_node) add_child(gui) player_controller = PLAYER_CONTROLLER.new() diff --git a/scenes/components/curved_line_2d.gd b/scenes/components/curved_line_2d.gd new file mode 100644 index 0000000..da07f82 --- /dev/null +++ b/scenes/components/curved_line_2d.gd @@ -0,0 +1,12 @@ +extends Node2D + +export(Curve2D) var curve +export(Color) var color = Color.red +export(float) var width = 2.0 + + +func _draw() -> void: + if curve == null: + return + + draw_polyline(curve.get_baked_points(), color, width) diff --git a/scenes/components/curved_line_2d.tscn b/scenes/components/curved_line_2d.tscn new file mode 100644 index 0000000..91c4788 --- /dev/null +++ b/scenes/components/curved_line_2d.tscn @@ -0,0 +1,6 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://scenes/components/curved_line_2d.gd" type="Script" id=1] + +[node name="CurvedLine2d" type="Node2D"] +script = ExtResource( 1 ) diff --git a/scenes/track_minimap.gd b/scenes/track_minimap.gd new file mode 100644 index 0000000..bf5c94f --- /dev/null +++ b/scenes/track_minimap.gd @@ -0,0 +1,90 @@ +extends Node2D + +export(Vector2) var size = Vector2(200, 200) +export(Texture) var player_icon + +onready var scaling_helper = $ScalingHelper +onready var track_path = $ScalingHelper/TrackPath +onready var track_line = $ScalingHelper/TrackLine +onready var start_line = $ScalingHelper/TrackPath/StartLine +onready var players_container = $ScalingHelper/Players + + +func _ready() -> void: + scaling_helper.position.x = size.x / 2 + scaling_helper.position.y = size.y / 2 + MultiplayerController.connect("peers_updated", self, "_on_peers_updated") + + +func set_curve(curve: Curve3D) -> void: + var curve2d = Curve2D.new() + var point_count = curve.get_point_count() + for point in range(point_count): + var point3d = curve.get_point_position(point) + var point_in = curve.get_point_in(point) + var point_out = curve.get_point_out(point) + curve2d.add_point( + Vector2(point3d.x, point3d.z), + Vector2(point_in.x, point_in.z), + Vector2(point_out.x, point_out.z) + ) + + var max_x = curve2d.get_baked_points()[0].x + var max_y = curve2d.get_baked_points()[0].y + var min_x = curve2d.get_baked_points()[0].x + var min_y = curve2d.get_baked_points()[0].y + for point in curve2d.get_baked_points(): + if point.x > max_x: + max_x = point.x + if point.x < min_x: + min_x = point.x + if point.y > max_y: + max_y = point.y + if point.y < min_y: + min_y = point.y + + var center_x = (max_x + min_x) / 2 + var center_y = (max_y + min_y) / 2 + var width = max_x - min_x + var height = max_y - min_y + var max_dim = max(width, height) + var scale_factor = size.x / (max_dim + track_line.width) + var new_center_x = scaling_helper.position.x - (center_x * scale_factor) + var new_center_y = scaling_helper.position.y - (center_y * scale_factor) + scaling_helper.scale.x = scale_factor + scaling_helper.scale.y = scale_factor + scaling_helper.position.x = new_center_x + scaling_helper.position.y = new_center_y + track_path.curve = curve2d + track_line.curve = curve2d + start_line.offset = 0.01 + + +func on_player_position_updated(player_id: int, position: Transform) -> void: + var existing_node: Sprite = players_container.get_node_or_null(String(player_id)) + if existing_node == null: + var player_color + if MultiplayerController.is_online(): + player_color = MultiplayerController.peers[player_id].color + else: + player_color = Color(1, 1, 1) + existing_node = Sprite.new() + existing_node.name = String(player_id) + existing_node.texture = player_icon + existing_node.modulate = player_color + players_container.add_child(existing_node) + existing_node.position.x = position.origin.x + existing_node.position.y = position.origin.z + existing_node.rotation = position.basis.x.signed_angle_to(Vector3.LEFT, Vector3.UP) + + +func _on_peers_updated() -> void: + for peer in MultiplayerController.peers: + var existing_node: Sprite = players_container.get_node_or_null(String(peer)) + if existing_node != null: + var player_color = MultiplayerController.peers[peer].color + existing_node.modulate = player_color + + for child in players_container.get_children(): + if not MultiplayerController.peers.has(int(float(child.name))): + child.queue_free() diff --git a/scenes/track_minimap.tscn b/scenes/track_minimap.tscn new file mode 100644 index 0000000..473c6ef --- /dev/null +++ b/scenes/track_minimap.tscn @@ -0,0 +1,37 @@ +[gd_scene load_steps=6 format=2] + +[ext_resource path="res://assets/player_icon.png" type="Texture" id=1] +[ext_resource path="res://scenes/track_minimap.gd" type="Script" id=2] +[ext_resource path="res://scenes/components/curved_line_2d.tscn" type="PackedScene" id=3] + +[sub_resource type="Gradient" id=1] +offsets = PoolRealArray( 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 ) +colors = PoolColorArray( 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1 ) + +[sub_resource type="GradientTexture" id=2] +gradient = SubResource( 1 ) +width = 50 + +[node name="TrackMinimap" type="Node2D"] +script = ExtResource( 2 ) +player_icon = ExtResource( 1 ) + +[node name="ScalingHelper" type="Node2D" parent="."] + +[node name="TrackPath" type="Path2D" parent="ScalingHelper"] +curve = null + +[node name="StartLine" type="PathFollow2D" parent="ScalingHelper/TrackPath"] +position = Vector2( -99.1171, -154.856 ) +rotation = -0.742965 + +[node name="Sprite" type="Sprite" parent="ScalingHelper/TrackPath/StartLine"] +rotation = 1.5708 +scale = Vector2( 1, 5 ) +texture = SubResource( 2 ) + +[node name="TrackLine" parent="ScalingHelper" instance=ExtResource( 3 )] +color = Color( 0.482353, 0, 0, 1 ) +width = 10.0 + +[node name="Players" type="Node2D" parent="ScalingHelper"] diff --git a/scenes/trackgui.gd b/scenes/trackgui.gd index 85ac67e..27427ef 100644 --- a/scenes/trackgui.gd +++ b/scenes/trackgui.gd @@ -8,6 +8,7 @@ onready var best_time_value = $VBoxContainer/HBoxContainer/BestTimeValue onready var wrong_way_label = $CenterContainer/WrongWayLabel onready var leaderboards = $VBoxContainer/LeaderboardsLine onready var leaderboards_list = $VBoxContainer/LeaderboardsLine/VBoxContainer/Leaderboards +onready var track_minimap = $VBoxContainer2/HBoxContainer/ViewportContainer/TrackRadar/TrackMinimap func _ready() -> void: @@ -15,6 +16,7 @@ func _ready() -> void: best_time_value.text = "NaN" if MultiplayerController.is_online(): leaderboards.visible = true + MultiplayerController.connect("peers_updated", self, "_on_peers_updated") else: leaderboards.visible = false @@ -47,7 +49,10 @@ func _format_time(time: float) -> String: remote func update_leaderboard_time(peer_id: String, lap_time: float): leaderboards_data[peer_id] = lap_time + _refresh_leaderboard() + +func _refresh_leaderboard(): var leaderboards_sorted = [] for peer in leaderboards_data: leaderboards_sorted.append([peer, leaderboards_data[peer]]) @@ -67,3 +72,19 @@ remote func update_leaderboard_time(peer_id: String, lap_time: float): func _leaderbords_comparison(left: Array, right: Array) -> bool: return left[1] < right[1] + + +func set_curve(curve: Curve3D) -> void: + track_minimap.set_curve(curve) + + +func on_player_position_updated(player_id: int, position: Transform) -> void: + track_minimap.on_player_position_updated(player_id, position) + + +func _on_peers_updated() -> void: + for peer in leaderboards_data.keys(): + if not MultiplayerController.peers.has(peer): + leaderboards_data.erase(peer) + + _refresh_leaderboard() diff --git a/scenes/trackgui.tscn b/scenes/trackgui.tscn index 18f7c5e..818607b 100644 --- a/scenes/trackgui.tscn +++ b/scenes/trackgui.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=5 format=2] +[gd_scene load_steps=6 format=2] [ext_resource path="res://assets/fonts/kenney-future-narrow.ttf" type="DynamicFontData" id=1] [ext_resource path="res://scenes/trackgui.gd" type="Script" id=2] +[ext_resource path="res://scenes/track_minimap.tscn" type="PackedScene" id=3] [sub_resource type="DynamicFont" id=1] size = 36 @@ -125,3 +126,30 @@ align = 1 __meta__ = { "_edit_use_anchors_": false } + +[node name="VBoxContainer2" type="VBoxContainer" parent="."] +margin_right = 984.0 +margin_bottom = 560.0 +alignment = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer2"] +margin_top = 360.0 +margin_right = 984.0 +margin_bottom = 560.0 +alignment = 2 + +[node name="ViewportContainer" type="ViewportContainer" parent="VBoxContainer2/HBoxContainer"] +margin_left = 784.0 +margin_right = 984.0 +margin_bottom = 200.0 + +[node name="TrackRadar" type="Viewport" parent="VBoxContainer2/HBoxContainer/ViewportContainer"] +size = Vector2( 200, 200 ) +transparent_bg = true +handle_input_locally = false +disable_3d = true +usage = 0 +render_target_update_mode = 3 +gui_disable_input = true + +[node name="TrackMinimap" parent="VBoxContainer2/HBoxContainer/ViewportContainer/TrackRadar" instance=ExtResource( 3 )] diff --git a/scenes/tracks/track.gd b/scenes/tracks/track.gd index df0319d..33627d5 100644 --- a/scenes/tracks/track.gd +++ b/scenes/tracks/track.gd @@ -24,6 +24,7 @@ var current_time = 0 var lap_done = false onready var checkpoints = $Checkpoints +onready var track_gui = $TrackGUI onready var path: Path = get_node(track_path) @@ -51,6 +52,7 @@ func _ready() -> void: gate.scale = gate_size checkpoints.get_child(0).add_child(gate) checkpoints.global_transform.origin = path.global_transform.origin + track_gui.set_curve(path.curve) func _process(_delta: float) -> void: @@ -96,3 +98,7 @@ func _build_checkpoint_collision(): func _update_time(): current_time = OS.get_ticks_msec() - start_time emit_signal("time_updated", current_time) + + +func _on_player_position_updated(player_id: int, position: Transform) -> void: + track_gui.on_player_position_updated(player_id, position) diff --git a/vehicles/vehicle.gd b/vehicles/vehicle.gd index f53a533..b6463d3 100644 --- a/vehicles/vehicle.gd +++ b/vehicles/vehicle.gd @@ -8,6 +8,7 @@ signal brake_updated(brake_percent) signal clutch_updated(clutch_percent) signal gear_updated(gear) signal steering_updated(steering_angle, steering_percent) +signal position_updated(player_id, position) enum GearRequest { NONE, UP, DOWN } @@ -256,6 +257,8 @@ func _physics_process(delta: float): steering = steering_input * lerp(max_steer_angle_rad, speed_steer_angle_rad, steer_speed_factor) emit_signal("steering_updated", steering, steering / max_steer_angle_rad) + emit_signal("position_updated", get_network_master(), global_transform) + if MultiplayerController.is_online(): if get_network_master() == get_tree().get_network_unique_id(): _synchronize() @@ -288,6 +291,7 @@ func _synchronize(): remote func sync_position(position: Transform): reset_transform = position + emit_signal("position_updated", get_network_master(), global_transform) remote func sync_inputs(remote_inputs):