From e6c1d4bf04d4dc288c56226de42a6eb44f1234e7 Mon Sep 17 00:00:00 2001 From: Kevin Schmidt Date: Mon, 10 Mar 2025 13:25:09 +0100 Subject: [PATCH] TD-11: Placement of Towers --- Justfile | 2 +- project.godot | 10 ++- scenes/game.tscn | 46 +++++++++++-- .../match/current_unix_time_message.gd | 12 ---- .../match/invalid_placement_message.gd | 13 ++++ scripts/channel/match/match_channel.gd | 30 ++++++-- .../match/request_tower_placing_message.gd | 11 +++ scripts/channel/match/tower_placed_message.gd | 13 ++++ scripts/match/map.gd | 65 ++++++++++++++++++ textures/tiles/tower.png | Bin 0 -> 161 bytes textures/tiles/tower.png.import | 34 +++++++++ tile_set.tres | 12 ++++ 12 files changed, 222 insertions(+), 26 deletions(-) delete mode 100644 scripts/channel/match/current_unix_time_message.gd create mode 100644 scripts/channel/match/invalid_placement_message.gd create mode 100644 scripts/channel/match/request_tower_placing_message.gd create mode 100644 scripts/channel/match/tower_placed_message.gd create mode 100644 scripts/match/map.gd create mode 100644 textures/tiles/tower.png create mode 100644 textures/tiles/tower.png.import create mode 100644 tile_set.tres diff --git a/Justfile b/Justfile index 2ccbb91..10ec597 100644 --- a/Justfile +++ b/Justfile @@ -3,7 +3,7 @@ _choose: lint: -gdlint . - -gdformat -d . + -gdformat . api_version := "v0.0.0-rc.4" api_location := "scripts/api-client" diff --git a/project.godot b/project.godot index 3f6dac5..2a39f9c 100644 --- a/project.godot +++ b/project.godot @@ -26,8 +26,6 @@ CurrentMatch="*res://scripts/match/current_match.gd" window/size/viewport_width=1920 window/size/viewport_height=1080 -window/stretch/mode="viewport" -window/stretch/aspect="expand" [editor_plugins] @@ -37,6 +35,14 @@ enabled=PackedStringArray("res://addons/format_on_save/plugin.cfg") theme/custom="res://ui/theme.tres" +[input] + +place={ +"deadzone": 0.0, +"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null) +] +} + [rendering] renderer/rendering_method="gl_compatibility" diff --git a/scenes/game.tscn b/scenes/game.tscn index f61971f..3b92862 100644 --- a/scenes/game.tscn +++ b/scenes/game.tscn @@ -1,13 +1,18 @@ -[gd_scene load_steps=3 format=3 uid="uid://co1x3hlc2efr6"] +[gd_scene load_steps=6 format=4 uid="uid://co1x3hlc2efr6"] [ext_resource type="Script" path="res://scripts/match/ui/opponent_name.gd" id="1_saby1"] [ext_resource type="Script" path="res://scripts/match/ui/current_game_time.gd" id="2_3jcub"] +[ext_resource type="TileSet" uid="uid://cvp867israfjk" path="res://tile_set.tres" id="3_0etcd"] +[ext_resource type="Script" path="res://scripts/match/map.gd" id="4_4c550"] + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_86u83"] +bg_color = Color(0.198848, 0.584132, 0.720474, 1) [node name="Game" type="Node2D"] -[node name="CanvasLayer" type="CanvasLayer" parent="."] +[node name="UI" type="CanvasLayer" parent="."] -[node name="HUD" type="Control" parent="CanvasLayer"] +[node name="HUD" type="Control" parent="UI"] layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 @@ -15,7 +20,7 @@ anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 -[node name="Opponent Name" type="RichTextLabel" parent="CanvasLayer/HUD"] +[node name="Opponent Name" type="RichTextLabel" parent="UI/HUD"] layout_mode = 1 anchors_preset = 5 anchor_left = 0.5 @@ -30,7 +35,7 @@ scroll_active = false autowrap_mode = 0 script = ExtResource("1_saby1") -[node name="Time" type="RichTextLabel" parent="CanvasLayer/HUD"] +[node name="Time" type="RichTextLabel" parent="UI/HUD"] layout_mode = 1 anchors_preset = 8 anchor_left = 0.5 @@ -47,3 +52,34 @@ fit_content = true scroll_active = false autowrap_mode = 0 script = ExtResource("2_3jcub") + +[node name="Seperator" type="Panel" parent="UI/HUD"] +custom_minimum_size = Vector2(4, 0) +layout_mode = 1 +anchors_preset = 13 +anchor_left = 0.5 +anchor_right = 0.5 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_styles/panel = SubResource("StyleBoxFlat_86u83") + +[node name="Camera" type="Camera2D" parent="."] + +[node name="Map" type="Node2D" parent="." node_paths=PackedStringArray("player_map", "player_tower_map", "opponent_map", "opponent_tower_map", "camera")] +script = ExtResource("4_4c550") +tile_set = ExtResource("3_0etcd") +player_map = NodePath("PlayerMap") +player_tower_map = NodePath("PlayerMap/Tower") +opponent_map = NodePath("OpentMap") +opponent_tower_map = NodePath("OpentMap/Tower") +camera = NodePath("../Camera") + +[node name="PlayerMap" type="Node2D" parent="Map"] + +[node name="Tower" type="TileMapLayer" parent="Map/PlayerMap"] + +[node name="OpentMap" type="Node2D" parent="Map"] + +[node name="Tower" type="TileMapLayer" parent="Map/OpentMap"] +tile_map_data = PackedByteArray("AAAAAAAAAQAAAAAAAAAAAAEAAQAAAAAAAAAAAAIAAQAAAAAAAAAAAAMAAQAAAAAAAAAAAAQAAQAAAAAAAAAAAAUAAQAAAAAAAAAAAAYAAQAAAAAAAAAAAAcAAQAAAAAAAAAAAAgAAQAAAAAAAAAAAAkAAQAAAAAAAAAAAAoAAQAAAAAAAAAAAAsAAQAAAAAAAAAAAAwAAQAAAAAAAAAAAA0AAQAAAAAAAAAAAA4AAQAAAAAAAAAAAA8AAQAAAAAAAAAAABAAAQAAAAAAAAAAABEAAQAAAAAAAAAAABIAAQAAAAAAAAAAABMAAQAAAAAAAAABAAAAAQAAAAAAAAABABMAAQAAAAAAAAACAAAAAQAAAAAAAAACABMAAQAAAAAAAAADAAAAAQAAAAAAAAADABMAAQAAAAAAAAAEAAAAAQAAAAAAAAAEABMAAQAAAAAAAAAFAAAAAQAAAAAAAAAFABMAAQAAAAAAAAAGAAAAAQAAAAAAAAAGABMAAQAAAAAAAAAHAAAAAQAAAAAAAAAHABMAAQAAAAAAAAAIAAAAAQAAAAAAAAAIABMAAQAAAAAAAAAJAAAAAQAAAAAAAAAJAAEAAQAAAAAAAAAJAAIAAQAAAAAAAAAJAAMAAQAAAAAAAAAJAAQAAQAAAAAAAAAJAAUAAQAAAAAAAAAJAAYAAQAAAAAAAAAJAAcAAQAAAAAAAAAJAAgAAQAAAAAAAAAJAAkAAQAAAAAAAAAJAAoAAQAAAAAAAAAJAAsAAQAAAAAAAAAJAAwAAQAAAAAAAAAJAA0AAQAAAAAAAAAJAA4AAQAAAAAAAAAJAA8AAQAAAAAAAAAJABAAAQAAAAAAAAAJABEAAQAAAAAAAAAJABIAAQAAAAAAAAAJABMAAQAAAAAAAAA=") diff --git a/scripts/channel/match/current_unix_time_message.gd b/scripts/channel/match/current_unix_time_message.gd deleted file mode 100644 index c6c16cb..0000000 --- a/scripts/channel/match/current_unix_time_message.gd +++ /dev/null @@ -1,12 +0,0 @@ -class_name CurrentUnixTimeMessage -extends Message - -const MESSAGE_ID: String = "CurrentUnixTime" - -@export var time: int -# gdlint:ignore = class-variable-name -@export var matchId: String - - -func get_message_id() -> String: - return MESSAGE_ID diff --git a/scripts/channel/match/invalid_placement_message.gd b/scripts/channel/match/invalid_placement_message.gd new file mode 100644 index 0000000..608fa35 --- /dev/null +++ b/scripts/channel/match/invalid_placement_message.gd @@ -0,0 +1,13 @@ +class_name InvalidPlacementMessage +extends Message + +enum Reason { OUT_OF_BOUNDS, LOCATION_USED } +const MESSAGE_ID: String = "InvalidPlacement" + +@export var x: int +@export var y: int +@export var reason: Reason + + +func get_message_id() -> String: + return MESSAGE_ID diff --git a/scripts/channel/match/match_channel.gd b/scripts/channel/match/match_channel.gd index 9bf6671..f359650 100644 --- a/scripts/channel/match/match_channel.gd +++ b/scripts/channel/match/match_channel.gd @@ -1,6 +1,7 @@ extends Channel -signal on_match_update(msg: CurrentUnixTimeMessage) +signal on_match_update(msg: TowerPlacedMessage) +signal on_invalid_placing(msg: InvalidPlacementMessage) func get_channel_location() -> String: @@ -12,9 +13,26 @@ func _process(_delta: float) -> void: if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN: return while self.socket.get_available_packet_count(): - var msg := CurrentUnixTimeMessage.deserialize( - self.socket.get_packet().get_string_from_utf8(), [CurrentUnixTimeMessage] + var msg: Message = ( + CurrentUnixTimeMessage + . deserialize( + self.socket.get_packet().get_string_from_utf8(), + [TowerPlacedMessage, InvalidPlacementMessage], + ) ) - if msg.get_message_id() != CurrentUnixTimeMessage.MESSAGE_ID: - return - on_match_update.emit(msg) + match msg.get_message_id(): + TowerPlacedMessage.MESSAGE_ID: + on_match_update.emit(msg) + InvalidPlacementMessage.MESSAGE_ID: + on_invalid_placing.emit(msg) + _: + continue + + +func send_request_place(x: int, y: int) -> void: + if self.socket.get_ready_state() != WebSocketPeer.STATE_OPEN: + return + var msg := RequestTowerPlacingMessage.new() + msg.x = x + msg.y = y + self.socket.send_text(Message.serialize(msg)) diff --git a/scripts/channel/match/request_tower_placing_message.gd b/scripts/channel/match/request_tower_placing_message.gd new file mode 100644 index 0000000..42f2a50 --- /dev/null +++ b/scripts/channel/match/request_tower_placing_message.gd @@ -0,0 +1,11 @@ +class_name RequestTowerPlacingMessage +extends Message + +const MESSAGE_ID: String = "RequestTowerPlacing" + +@export var x: int +@export var y: int + + +func get_message_id() -> String: + return MESSAGE_ID diff --git a/scripts/channel/match/tower_placed_message.gd b/scripts/channel/match/tower_placed_message.gd new file mode 100644 index 0000000..8d11c46 --- /dev/null +++ b/scripts/channel/match/tower_placed_message.gd @@ -0,0 +1,13 @@ +class_name TowerPlacedMessage +extends Message + +enum GamePlayerMaps { PLAYER, OPPONENT } +const MESSAGE_ID: String = "TowerPlaced" + +@export var x: int +@export var y: int +@export var map: GamePlayerMaps + + +func get_message_id() -> String: + return MESSAGE_ID diff --git a/scripts/match/map.gd b/scripts/match/map.gd new file mode 100644 index 0000000..33da388 --- /dev/null +++ b/scripts/match/map.gd @@ -0,0 +1,65 @@ +extends Node2D + +@export var tile_set: TileSet +@export var player_map: Node2D +@export var player_tower_map: TileMapLayer +@export var opponent_map: Node2D +@export var opponent_tower_map: TileMapLayer +@export var map_size := Vector2i(10, 20) +@export var camera: Camera2D + +var clicked: bool = false +var clicked_pos: Vector2 + + +func _ready() -> void: + player_tower_map.tile_set = tile_set + opponent_tower_map.tile_set = tile_set + player_tower_map.clear() + opponent_tower_map.clear() + MatchChannel.connect("on_match_update", on_match_update) + + +func _process(_delta: float) -> void: + # gdlint:ignore = max-line-length + var new_zoom := float(get_window().size.y) / float(map_size.y * tile_set.tile_size.y) + camera.zoom = Vector2(new_zoom, new_zoom) + var new_base_postion := get_window().size / 2 / new_zoom + camera.position = new_base_postion + + self.position.x = new_base_postion.x - map_size.x * tile_set.tile_size.x + opponent_map.position.x = map_size.x * tile_set.tile_size.x + + +func _input(_event) -> void: + if Input.is_action_just_pressed("place"): + clicked_pos = get_global_mouse_position() + clicked = true + + +func _physics_process(_delta: float) -> void: + if clicked: + clicked = false + var pos: Vector2i = world_to_game_pos(clicked_pos) + if pos == Vector2i(-1, -1): + return + MatchChannel.send_request_place(pos.x, pos.y) + + +func on_match_update(msg: TowerPlacedMessage) -> void: + if msg.map == TowerPlacedMessage.GamePlayerMaps.PLAYER: + player_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0)) + else: + opponent_tower_map.set_cell(Vector2i(msg.x, msg.y), 1, Vector2i(0, 0)) + + +func world_to_game_pos(world_pos: Vector2) -> Vector2i: + if ( + world_pos.x < self.position.x + || world_pos.x > self.position.x + map_size.x * tile_set.tile_size.x + ): + return Vector2i(-1, -1) + return Vector2i( + (world_pos.x - self.position.x) / tile_set.tile_size.x, + world_pos.y / tile_set.tile_size.y, + ) diff --git a/textures/tiles/tower.png b/textures/tiles/tower.png new file mode 100644 index 0000000000000000000000000000000000000000..8f13831470d4b63160fdcb0ce7079ecbe4a4889d GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?31We{epSZZGe6twho zaSVyze0#x>m%)I8#j#7LkBHIRR)33;iG@Qz!J&Zx%1B`F qlVn;Scz(Ag&=9`V2+uTMUj{88n*)eJ;8O5p5asFW=d#Wzp$PydZ6wzK literal 0 HcmV?d00001 diff --git a/textures/tiles/tower.png.import b/textures/tiles/tower.png.import new file mode 100644 index 0000000..a23198c --- /dev/null +++ b/textures/tiles/tower.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bj8jwha8g5y8n" +path="res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://textures/tiles/tower.png" +dest_files=["res://.godot/imported/tower.png-afe2561faadc2586f630d8a5c5939231.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/tile_set.tres b/tile_set.tres new file mode 100644 index 0000000..aa744eb --- /dev/null +++ b/tile_set.tres @@ -0,0 +1,12 @@ +[gd_resource type="TileSet" load_steps=3 format=3 uid="uid://cvp867israfjk"] + +[ext_resource type="Texture2D" uid="uid://bj8jwha8g5y8n" path="res://textures/tiles/tower.png" id="1_4stpq"] + +[sub_resource type="TileSetAtlasSource" id="TileSetAtlasSource_tivyh"] +texture = ExtResource("1_4stpq") +texture_region_size = Vector2i(32, 32) +0:0/0 = 0 + +[resource] +tile_size = Vector2i(32, 32) +sources/1 = SubResource("TileSetAtlasSource_tivyh")